闽公网安备 35020302035485号
<?php
# 堆代码 duidaima.com
$connect = mysqli_connect("localhost", "root", "123456", "blog", "3306") or die("数据库连接失败!");
$connect->set_charset("utf8");
$id = 1;
$sql = "SELECT * FROM article WHERE id = $id";
$query = mysqli_query($connect, $sql);
if (!$query) {
die("数据库查询失败!");
}
$assoc = $query->fetch_assoc();
var_dump($assoc);
上面的写法有一些缺点,有一种更好的方式是使用PDO,扩展性更强,而且可以使用预处理防止SQL注入:<?php
try {
$pdo = new PDO("mysql:host=localhost;dbname=blog", "root", "123456");
} catch (PDOException $exception) {
echo "Connect Failed" . $exception->getMessage();
}
$pdo->exec("set names utf8");
$id = 1;
$prepare = $pdo->prepare("SELECT * FROM article WHERE id = ?");
$prepare->execute(array($id));
while ($row = $prepare->fetch()) {
var_dump($row);
}
不过实际开发中,大家都是使用一些封装好的类和方法,比如laravel框架里面称之为查询构造器,我们可以使用这样方法去查询数据库:<?php
$users = DB::table('users')->get();
$price = DB::table('orders')->where('finalized', 1)->avg('price');
$users = DB::table('users')
->join('contacts', 'users.id', '=', 'contacts.user_id')
->join('orders', 'users.id', '=', 'orders.user_id')
->select('users.*', 'contacts.phone', 'orders.price')
->get();
$orders = DB::table('orders')
->select('department', DB::raw('SUM(price) as total_sales'))
->groupBy('department')
->havingRaw('SUM(price) > 2500')
->get();
还有比如说TP框架里面M方法,这些类和方法大大简化了查询操作,但本质上还是拼SQL,只不过调用的时候看起来更像面向对象,方便很多。但是这些并不是真正意义上的ORM,最多只算得上是O(object),它只是把数据库查询操作对象化了,但是没有解决对象之间的关系问题!{
"require": {
"doctrine/orm": "^2.6.2",
"symfony/yaml": "2.*"
}
}
2.在项目根目录创建一个bootstrap.php文件:<?php
// bootstrap.php
use Doctrine\ORM\Tools\Setup;
use Doctrine\ORM\EntityManager;
require_once "vendor/autoload.php";
// Create a simple "default" Doctrine ORM configuration for Annotations
$isDevMode = true;
$config = Setup::createAnnotationMetadataConfiguration(array(__DIR__."/src"), $isDevMode);
// or if you prefer yaml or XML
//$config = Setup::createXMLMetadataConfiguration(array(__DIR__."/config/xml"), $isDevMode);
//$config = Setup::createYAMLMetadataConfiguration(array(__DIR__."/config/yaml"), $isDevMode);
// database configuration parameters
$conn = array(
'dbname' => 'blog',
'user' => 'root',
'password' => '123456',
'host' => 'localhost',
'driver' => 'pdo_mysql',
'charset' => 'utf8',
);
// obtaining the entity manager
$entityManager = EntityManager::create($conn, $config);
这里面有一些需要注意的地方,$idDevMode是配置是否开发模式。<?php // cli-config.php require_once "bootstrap.php"; return \Doctrine\ORM\Tools\Console\ConsoleRunner::createHelperSet($entityManager);这样就可以使用命令行工具执行一些操作,比如说生成数据表,更新数据表
<?php
namespace App;
/**
* @Entity @Table(name="products",options={"collate"="utf8mb4_unicode_ci", "charset"="utf8mb4"})
* Class Product
* @package App
*/
class Product
{
/**
* @ID @Column(type="integer") @GenerateDValue
* @var int
*/
protected $id;
/**
* @Column(type="string")
* @var string
*/
protected $name;
/**
* @return int
*/
......more code
}
后面的setter和getter这里省略了,如果有人对 annotation 这种注解方法比较熟悉的话应该可以看懂上面那些注释的意思。首先在类的注释上,使用了@Entity表明这是一个数据库实体。@Table指定了表名,@ID表明的是主键,@Column表明是数据表字段,使用type声明了类型!The following SQL statements will be executed:
CREATE TABLE products (id INT NOT NULL, name VARCHAR(255) NOT NULL, PRIMARY KEY(id)) DEFAULT CHARACTER SET utf8 COLLATE utf8_unicode_ci ENGINE = InnoDB;
Updating database schema...
1 query was executed
[OK] Database schema updated successfully!
使用这种方式建表不用去写SQL语句,无论是mysql还是sql server,或者oracle,都没问题,一键迁移,ORM抹平了数据库之间的差异!<?php
require "vendor/autoload.php";
require "bootstrap.php";
$product = new \App\Product();
$product->setName("ORM的应用");
$entityManager->persist($product);
$entityManager->flush();
echo "Created Product Success with ID: ".$product->getId();
var_dump($product);
可以看出来这是一个完全OOP的写法,是先实例化一个数据表实体,然后通过setter去设置去属性,最后调用persist和flush持久化数据库里面。<?php
//查询所有
$productRepository = $entityManager->getRepository('\App\Product');
$products = $productRepository->findAll();
foreach ($products as $product) {
var_dump($product);
var_dump($product->getName());
}
//查询单个
$id = 3;
$product = $entityManager->find('Product', $id);
if ($product === null) {
echo "No product found.\n";
exit(1);
}
var_dump($product);
如果想对数据进行修改也很简单,比如在上面的例子里面,我们查询出id为3的数据,现在我们想修改这条数据:<?php
$product->setName("ORM更新数据");
$entityManager->flush();
我们只需调用这个对象的setter方法,然后flush即可!
第三种: 新建一个中间表,用来维护2个表之间的关系,中间表一般用来维护多对多的关系,但是也可以用于1对多的关系,这时候查询和修改都比较复杂,好处就是很容易扩展成多对多关系!
<?php
namespace App;
/**
* @Entity @Table(name="comments",options={"collate"="utf8mb4_unicode_ci", "charset"="utf8mb4"})
* Class Product
* @package App
*/
class Comment
{
/**
* 这里通过注释设置了需要映射的实体和对应的字段
* @ManyToOne(targetEntity="Product", inversedBy="comments")
* @JoinColumn(name="product_id", referenceColumnName="id")
* @var Product
*/
protected $product;
/**
* @return Product
*/
public function getProduct(): Product
{
return $this->product;
}
/**
* @param Product $product
* @return self
*/
public function setProduct(Product $product): self
{
$this->product = $product;
return $this;
}
/**
* @ID @Column(type="integer") @GenerateDValue
* @var int
*/
protected $id;
/**
* @Column(type="string")
* @var string
*/
protected $content;
.......more code
}
但是多了一个属性 product, 因为这种1对多的关系对评论来说就是一个评论拥有一个产品,但是一个产品可以拥有多个评论。同理,我们就需要对 product 实体做一些改动,加入了一个comments属性和一些注解!<?php
/**
* @oneToMany(targetEntity="Comment", mappedBy="product")
* @var
*/
protected $comments;
public function __construct()
{
$this->comments = new ArrayCollection();
}
执行 vendor/bin/doctrine orm:schema-tool:update --force --dump-sql更新数据库, 执行之后你会发现comments表会多一个product_id字段, 同时还会多出一个外键索引!<?php
$id = 3;
$product = $entityManager->find('\App\Product', $id);
$comment = new \App\Comment();
$comment->setContent("这是一条评论!");
$comment->setProduct($product);
$entityManager->persist($comment);
$entityManager->flush();
执行以上代码,查看数据表你会发现comments表会自动增加一条记录,其product_id为3,在代码里面我们并没有手动去设置product_id,ORM替我们自动完成了这些操作!下面再看查询一个产品的所有评论,操作也是相当简单的:<?php
$id = 3;
$product = $entityManager->find('\App\Product', $id);
$comments = $product->getComments()->toArray();