我在确定如何从数据库表中访问数据时遇到了一些麻烦。我知道有很多框架可以促进这一点,例如Yii,但我试图避免这条路线,因为它与我团队中的其他人的学习曲线和时间限制。
假设我有一个名为File
的表,其中包含一个包含其名称,上传日期,上传用户等的文件列表。我还有另一个名为Versions
的表,它基本上包含每个文件' s version:当用户上传同一个文件时,会将其视为修订版。
文件
fid | name | uploadDate
1 | test | 2017-01-01
2 | test2 | 2017-01-01
版本
vid | fid | user
1 | 1 | a
2 | 1 | b
我最初的想法是为每个表创建一个类,我将在fid
构造函数中放入Files
并检索该单行并对Versions
执行相同的操作,其中vid
将放在构造函数中并检索特定版本。
然而,这意味着我将有两个单独的查询,每个类一个。所以我想的可能是将它们合二为一。这意味着我将在Files
类中的一个查询(使用LEFT JOIN)下检索文件信息和版本信息,然后使用Versions
类来处理数据而不是查询数据库并处理数据。
出于某种原因,我觉得这样有更好的表现,因为我使用JOINS来帮助我,但另一方面,如果我只需要特定版本文件的信息,我需要创建File
的实例,这意味着使用fid
THEN从内部检索我想要的版本。 (< - 措辞不佳)。
也许有人可以给我一些关于这种方式的见解,以及在无法访问框架时该怎么做。
答案 0 :(得分:1)
ORM无法解决您的所有问题
在许多情况下,使用模型访问数据库很方便,但并非总是如此。您可能更好地保持ORM模型不受需要复杂查询和高性能的任务的影响。
正确使用ORM模式
ORM只是您可以在代码中使用的众多编码模式之一。
阅读此主题以了解有关它的更多信息What is an ORM and where can I learn more about it?
您不应将ORM视为隔离数据库访问的应用程序层。它只是一种以面向对象的方式操作数据的技术。
在每个流行的框架中,您都会看到ORM是一个选项,而不是强制层。
考虑您希望获取特定文件的所有版本的情况。使用方法FileVersionManager
创建类似getAllVersions
singleton的内容,该方法将fid
执行JOIN查询。这里也可以是checkoutToVersion
或getPreviousVersion
。此方法可以返回一个或一组Version
ORM模型。重要的是 - 这种方式在语义上更有意义,因此更容易阅读和理解其他程序员。
或者如果您需要在每个文件更改上生成版本,您可以将此逻辑委托给类似Versionable
行为或类似的东西。
我更喜欢将ORM视为某种应用程序域定义层。
所以,回答你的问题
如果您想要自己的ORM实现,那么不要太复杂。使用CRUD方法和模式定义为每个表创建单独的ORM模型。并使用其他模式执行复杂查询。
示例(应该实现Query.selectWhere
以使示例正常工作):
<?php
/**
* @property $name
**/
class File extends ORMModel
{
public function tableName()
{
return 'files';
}
public function properties()
{
return array_merge(parent::properties(), ['name']);
}
}
/**
* @property $number
* @property $file_id
**/
class Version extends ORMModel
{
public function tableName()
{
return 'versions';
}
public function properties()
{
return array_merge(parent::properties(), ['file_id', 'number']);
}
public function getFile()
{
return new File($this->file_id);
}
}
class FileVersionManager
{
public static function getLatestVersion($file)
{
$query = new Query();
$rows = $query->selectWhere((new Version())->tableName(), ['file_id' => $file->id]);
$max = 0;
$maxId = null;
foreach ($rows as $row) {
if ($row['number'] > $max) {
$maxId = $row['id'];
$max = $row['number'];
}
}
return new Version($maxId);
}
public static function createNewVersion($file)
{
$latestVersion = static::getLatestVersion($file);
$newVersion = new Version();
$newVersion->file_id = $file->id;
$newVersion->number = $latestVersion->number + 1;
$newVersion->insert();
return $newVersion;
}
}
class Query
{
private static $datasource = [
'files' => [
1 => [
'name' => 'file1',
],
2 => [
'name' => 'file1',
]
],
'versions' => [
1 => [
'file_id' => 1,
'number' => 1
],
2 => [
'file_id' => 1,
'number' => 2
],
3 => [
'file_id' => 2,
'number' => 1
],
4 => [
'file_id' => 2,
'number' => 2
],
]
];
public function select($tablename) {
return static::$datasource[$tablename];
}
public function selectOne($tablename, $id) {
return @static::$datasource[$tablename][$id];
}
public function selectWhere($tableName, $condition) {
//@todo: implement selection assuming that condition is ['propertyName1' => 'propertyValue1', 'propertyName2' => 'propertyValue2', ]
//should retun array of properties including id for above example
return [];
}
public function update($tableName, $id, $values) {
if (empty(static::$datasource[$tableName][$id])) return false;
static::$datasource[$tableName][$id] = $values;
return true;
}
public function insert($tableName, $values) {
$id = max(array_keys(static::$datasource[$tableName])) + 1;
static::$datasource[$tableName][$id] = $values;
return $id;
}
public function delete($tableName, $id)
{
unset(static::$datasource[$tableName][$id]);
return true;
}
}
/**
* @property $id
**/
abstract class ORMModel
{
private $properties;
public abstract function tableName();
public function properties() {
return ['id'];
}
public function __get($name) {
$propertyNames = $this->properties();
if (in_array($name, $propertyNames)) {
return @$this->properties[$name];
}
}
public function __set($name, $value) {
$propertyNames = $this->properties();
if (in_array($name, $propertyNames)) {
$this->properties[$name] = $value;
}
}
public function __construct($id = null)
{
if (!empty($id)) {
$query = new Query();
if ($this->properties = $query->selectOne($this->tableName(), $id)) {
$this->properties['id'] = $id;
}
}
}
public function insert()
{
$query = new Query();
$id = $query->insert($this->tableName(), $this->properties);
$this->properties['id'] = $id;
return $this;
}
public function update()
{
if (empty($this->properties['id'])) return false;
$query = new Query();
return $query->update($this->tableName(), $this->id, array_diff($this->properties, ['id']));
}
public function delete()
{
if (empty($this->properties['id'])) return false;
$query = new Query();
return $query->delete($this->tableName(), $this->id);
}
}
$version = new Version(1);
$file = $version->getFile();
var_dump($file->name);
$file = new File(2);
$version = FileVersionManager::getLatestVersion($file);
var_dump($version->number);
FileVersionManager::createNewVersion($file);
$version = FileVersionManager::getLatestVersion($file);
var_dump($version->number);
P.S。您可以在这里定义自己的Query
实施,这应该适用于您的(任意)数据源
PPS 我仍然建议您学习一些流行的框架(Yii2,Laravel,Symfony或其他任何框架),因为这是学习构建应用程序架构的最佳实践的好方法