CodeIgniter 下引入ORM Doctrine

做了两年的CI开发,一直使用activeRecord来操作数据库。简单,轻巧加方便。最近一个项目交给手下去做,也是采用从数据库设计入手的开发流程,现在已经上线运行。经历了理清需求,设计数据库,在CI中建立model, controller,需求变更,更改数据库,更改代码,增加需求,更改数据库等过程。回头来看,当需要了解全局代码和业务逻辑需求时,还是得从数据库入手,突然有一种厌烦的感脚:对象的属性都在数据库里,而相关的操作在代码中,觉得很分裂。回想多年前开发的C#与JAVA中都有一些好用的ORM的框架,对我来说,ORM最大的好处是隐藏数据库,项目前期设计时根据需求来设计对象,轻装上阵,不必早早地陷入增改删查中;直接利用工具将对象映射到数据库中;数据库的增改删查也都是面向对象的。

可能存在的两点顾虑:

  1. 既然要由对象自动映射到数据库,自然要遵守一套metaData规则才行。
  2. 性能问题,由ORM自动生成sql语句,性能可能不如以前。但对比框架的可读性/可维护性与少许的硬件性能成本,还是选择框架优先。另外,相信ORM的90%的性能影响不大,少许的实在ORM解决不了的问题也能提供原生的sql来解决,总体来说,是利大于弊。

(官方参考文档:http://doctrine-orm.readthedocs.org/en/latest/tutorials/getting-started.html

开始吧,我们的目的是什么,没有蛀牙!好吧,这只是我们的一个目的,还在其它的目的:

  • 根据建立的对象生成数据库;
  • 新增对象持久化到数据库中;
  • 能使用entity来方便查询数据里的信息并达到更改。

1. 在CI下安装doctrine

a. 最新的CI 3.0已支持composer。在application文件夹下建立composer.son文件如下。(不是在CI根目录下)。 注意autoload参数(不是官方例子中的/src/文件夹)

{
    "require": {
        "doctrine/orm": "2.4.*",
        "symfony/yaml": "2.*"
    },
    "autoload": {
        "psr-0": {"": "models/entities"}
    }
}

notes: 上面autoload参数很重要,因为doctrine的启动需要指明entity目录,原始例子中给定的是/src,这里我们放在CI的model/entities目录下,另外,同时创建model/generated 与 models/proxies目录,generated目录用来由数据库生成entity,proxies目录用来存放lazy load需要生成的代码.

b. 安装doctrine: composer install. 安装后目录结构如下:

      

2. 配置bootstrap与cli-config

在doctrine中,bootstrap负责创建entityManager,entityManager是整个doctrine对外提供的操作接口: 隐藏数据库接口,提供了对entity的查询,更新及持久化。

在bootstrap中,首先使用composer自带的功能对整个doctrine实现加载。(这里保留了composer功能,实现将doctrine引入到CI修改最小化)

创建基本的entityManager只需要两步:

  1. 使用setup创建config。
  2. 初始化数据库配置对象。

使用数据库连接对象创建entityManager后我们可能及不可耐就想用来从对象来逆向工程数据库了。别急,慢慢来。

<?php
// bootstrap.php
use Doctrine\ORM\Tools\Setup;
use Doctrine\ORM\EntityManager;
use Doctrine\Common\ClassLoader,
    Doctrine\DBAL\Logging\EchoSQLLogger,
    Doctrine\Common\Cache\ArrayCache;

date_default_timezone_set("Asia/Shanghai");

require_once "vendor/autoload.php";

// database configuration parameters
if(defined(APPPATH))
{
    require_once APPPATH.‘config/database.php‘;
    $conn = array(
            ‘driver‘ => ‘pdo_mysql‘,
            ‘user‘ =>     $db[‘default‘][‘username‘],
            ‘password‘ => $db[‘default‘][‘password‘],
            ‘host‘ =>     $db[‘default‘][‘hostname‘],
            ‘dbname‘ =>   $db[‘default‘][‘database‘]
        );
}
else
{
    $conn = array(
    ‘driver‘ => ‘pdo_mysql‘,
    ‘user‘ =>     ‘root‘,
    ‘password‘ => ‘‘,
    ‘host‘ =>     ‘127.0.0.1‘,
    ‘dbname‘ =>   ‘doctrine‘
);
}
//Below can be exected in cli
/*
require_once APPPATH.‘vendor/Doctrine/Common/lib/doctrine/common/ClassLoader.php‘;
$doctrineClassLoader = new ClassLoader(‘Doctrine‘,  APPPATH.‘libraries‘);
$doctrineClassLoader->register();
$entitiesClassLoader = new ClassLoader(‘models‘, rtrim(APPPATH, "/" ));
$entitiesClassLoader->register();
$proxiesClassLoader = new ClassLoader(‘Proxies‘, APPPATH.‘models/proxies‘);
$proxiesClassLoader->register();
*/

// Create a simple "default" Doctrine ORM configuration for Annotations
$isDevMode = true;
$config = Setup::createAnnotationMetadataConfiguration(array(__DIR__."/models/entities"), $isDevMode);
// or if you prefer yaml or XML
//$config = Setup::createXMLMetadataConfiguration(array(__DIR__."/config/xml"), $isDevMode);
//$config = Setup::createYAMLMetadataConfiguration(array(__DIR__."/config/yaml"), $isDevMode);

$cache = new ArrayCache;
$config->setMetadataCacheImpl($cache);
$driverImpl = $config->newDefaultAnnotationDriver(array(__DIR__.‘/models/entities‘));
$config->setMetadataDriverImpl($driverImpl);
$config->setQueryCacheImpl($cache);

$config->setQueryCacheImpl($cache);

// Proxy configuration
$config->setProxyDir(__DIR__.‘/models/proxies‘);
$config->setProxyNamespace(‘Proxies‘);

// Set up logger
//$logger = new EchoSQLLogger;
//$config->setSQLLogger($logger);
$config->setAutoGenerateProxyClasses( TRUE );

// obtaining the entity manager
global $entityManager;
$entityManager = EntityManager::create($conn, $config);

要让entityManager知道用哪里的对象来进行反向工程,下面这句就尤为重要了:

$config = SetupcreateAnnotationMetadataConfiguration(array(DIR."/models/entities"), $isDevMode);

(在这里也提一下,当从数据库生成entity时当然也要指明entity要放在哪个文件夹了,使用的是EntityGenerator对象,使用该对象的generate方法时指定存放的文件夹就可以了。)

官方文档中使用的是命令行的方法来进行反向工程的,我们这里也依样画葫芦,接下来创建必要的cli-config文件。这个文件相对来讲就没有bootstrap那么长了,总公只有下面两行即可:

requireonce "bootstrap.php";

return DoctrineORMToolsConsoleConsoleRunnercreateHelperSet($entityManager);

反向工程使用vendor/bin/中的doctrine命令:

vendor/bin/doctrine

其中常用的有如下:

vendor/bin/doctrine orm:schema-tool:create

vendor/bin/doctrine orm:schema-tool:update --force

notes: 使用update命令新增字段不会影响原先的数据。

好吧,是不是急不可奈要试一试了,输入第一条create命令,咦,不好出现一个错误 “No Metadata Classes to process.” ,心跳加快,冷静,这是正常的,是因为我们还没建立我们想要的entity呢。

建立entity进行反向工程

1. 在/models/entities中建立我们第一个entity: Product.php

注意这里的每一个属性都protected属性,对应都有一对mutator(getter与setter)这是有什么用处的呢?由官方文档所说是用来方便doctrine来产生entity,而不是使用entity.field=foo的方式。具体在doctrine如何操作的有待进一步探索。对于主键Id是没有setter方法的,你懂的。

2. 现在我们只是定义了对象,但数据库构造是需要一些数据库属性的,类名与属性前面的metadata就是来干这个的。(定义的表名,对象属性对应的数据库字段名与字段属性)

<?php
// src/Product.php
/**
 * @Entity @Table(name="products")
 **/
class Product
{
    /** @Id @Column(type="integer") @GeneratedValue **/
    protected $id;

    /** @Column(type="string") **/
    protected $name;

    public function getId()
    {
        return $this->id;
    }

    public function getName()
    {
        return $this->name;
    }

    public function setName($name)
    {
        $this->name = $name;
    }
}

3. 下面我们就可以使用下面命令来进行反向工程了,是不是很兴奋!

vendor/bin/doctrine orm:schema-tool:update --force --dump-sql

4. 下面我们就来建立一段脚本来生成一个product并将其插入数据(持久化),你就会发现如何面向对象,隐藏数据库操作的了。

  1. <?php
    require_once "bootstrap.php";
    
    $newProductName = $argv[1];
    
    $product = new Product();
    $product->setName($newProductName);
    
    $entityManager->persist($product);
    $entityManager->flush();
    
    echo "Created Product with ID " . $product->getId() . "\n";

5. 下面我们就要使用cli来运行这段php脚本调用ORM框架来插入product了。

  1. $ php createproduct.php ORM
    $ php createproduct.php DBAL

查看数据库,是不是发现了新的数据已经插入了,ok大功告成。

时间: 10-19

CodeIgniter 下引入ORM Doctrine的相关文章

BroadLeaf 下定义ORM对象:Province,City,Area

要点:BroadLeaf框架下定义ORM对象需要先定义一个接口, 然后在persistence-unit 的配置中进行声明,如不声明会报错:no persistent classes found for query class IProvince: import java.io.Serializable; import javax.annotation.Nonnull; public interface IProvince extends Serializable{ @Nonnull publi

Nodejs Express下引入本地文件的方法

Express的结构如下: |---node_modules------用于安装本地模块. |---public------------用于存放用户可以下载到的文件,比如图片.脚本文件.样式表等.     |---routes------------用于存放路由文件.     |---views-------------用于存放网页的模板.     |---app.js------------应用程序的启动脚本.     |---package.json------项目的配置文件. 从上述结构中

iOS——在ARC下引入MRC文件

在写一些工程时我们总是要引入一些第三方文件,但是这些文件有些是MRC下的有些是ARC下的.所以我们要进行转换. 引入三方文件时首先要阅读引入的文件的.h 文件头部信息 如下面的文件:头部文件要求:Header Search Paths包含/usr/include/libxml2 Other Linker Flags包含-lxml2 所以 在Bulid Setting下进行搜索 搜索后对其进行修改 对.h文件所要求的路径进行一一添加,添加完成后,就是把让MRC得文件在ARC的工程下进行运行 首先在

python(十二)下:ORM框架SQLAlchemy使用学习

此出处:http://blog.csdn.net/fgf00/article/details/52949973 本节内容 ORM介绍 sqlalchemy安装 sqlalchemy基本使用 多外键关联 多对多关系 表结构设计作业  一.ORM介绍 如果写程序用pymysql和程序交互,那是不是要写原生sql语句.如果进行复杂的查询,那sql语句就要进行一点一点拼接,而且不太有重用性,扩展不方便.而且写的sql语句可能不高效,导致程序运行也变慢. 为了避免把sql语句写死在代码里,有没有一种方法直

common规范下引入文件的四种方式

1.引入文件夹,这个文件夹(aa)的位置在当前文件夹node_modules下. 因为node_modules文件内的文件引入时可以直接写文件名,不需要使用  ./node_modules/aa    的格式. 2.在当前文件夹目录下载jquery包,下载完成后也存在当前文件夹下,所以可以直接引入. 3.引入当前文件夹下的文件,需要在文件名前加(./). 4.引入当前文件夹下的文件夹,需要在文件夹名前加(./). 原文地址:https://www.cnblogs.com/myhanyu/p/93

CodeIgniter怎么引入公共的头部或者尾部文件(实现随意引入或分区域创建header.html,bodyer.html,footer.html)

除非你天赋异禀,凡事基本对任何人来说都是开头难的,且开头的事情如果没有做好 往往会打掉一个人对于某件事的希望及其激情,所以咱们先从容易的事情开始慢慢建立自己 信心.后面的事情咱们再慢慢推进. 如果你是刚入CodeIgniter这个门,建议一开始先按照我这种搭建环境方法进行创建. 1.首先创建一个叫template.php文件放入你的views项目文件夹. template.php中的代码如下 <?php $this->load->view('header'); $this->loa

记webpack下引入vue的方法(非.vue文件方式)

直接script引入下载静态的vue.js文件则最后用copy-webpack-plugin复制到一样的目录即可 使用npm安装的vue无法直接用 import vue from "vue",因为这样引用的是vue.common.js查资料:为什么会引 vue.common.js,from 'vue' 不该引的是 vue.js 么?这就要引入另一个知识点:package.json.package.json 中的 main 属性决定了,当项目被引入时,输出的是哪个文件,而 vue 的 p

eclipse如何在不联网的情况下引入dtd约束文件

1. 获取dtd文件,解压 F:\Java配置文件\Mybatis\mybatis-3.3.0\mybatis-3.3.0.jar\org\apache\ibatis\builder\xml\ 路径下的dtd文件 2. windows > Preferences >Xml > Xml Catalog 3. 点击Add 原文地址:https://www.cnblogs.com/xianya/p/9345948.html

虚拟机 下引入中文

以前试过一点方法下载了文件包 都没有成功 然后呢  今天总结一下: 关于这个简单的设置一次就好