ORM 不会解决你所有的问题
在许多情况下,使用模型访问数据库很方便,但并非总是如此。对您而言,让您的 ORM 模型免于需要复杂查询和高性能的任务可能会更好。
正确使用 ORM 模式
ORM 只是您可以在代码中使用的众多编码模式之一。
阅读此主题以了解更多信息What is an ORM and where can I learn more about it?
您不应将 ORM 视为隔离对数据库的访问的应用程序层。它只是一种以面向对象的方式操作数据的技术。
在每个流行的框架中,您都会看到 ORM 是一个选项,而不是一个强制层。
当您想要获取特定文件的所有版本时,请考虑这种情况。使用getAllVersions 方法创建类似FileVersionManager 的单例,它将通过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 实现,这应该适用于您的(任何)数据源
P.P.S.我仍然建议你学习一些流行的框架(Yii2、Laravel、Symfony 或任何其他),因为这是学习构建应用程序架构的最佳实践的好方法