我在确定如何从数据库表中访问数据时遇到了一些麻烦。我知道有很多框架可以促进这一点,例如Yii,但是我试图避免这条路线,因为它与我团队中的其他人的学习曲线和时间限制。
假设我有一个名为File的表,其中包含一个包含其名称,上传日期,上传用户等的文件列表。我还有另一个名为Versions的表,它基本上保存了每个文件的版本:当用户上传相同的文件时,它将其视为修订版。
档
fid | name | uploadDate
1 | test | 2017-01-01
2 | test2 | 2017-01-01
版本
vid | fid | user
1 | 1 | a
2 | 1 | b
我最初的想法是为每个表创建一个类,我将在Files构造函数中抛出fid并检索该单行并对Versions执行相同操作,其中将放入vid构造函数并检索特定版本。
但是,这意味着我将有两个单独的查询,每个类一个。所以我想的可能是将它们合二为一。这意味着我将在Files类中的一个查询(使用LEFT JOIN)下检索文件信息和版本信息,然后使用Versions类来处理数据,而不是查询数据库并处理数据数据。
出于某种原因,我觉得这有更好的性能,因为我使用JOINS帮助我在这里,但另一方面,如果我只需要信息的特定版本的文件,我需要创建一个实例File,表示使用fid THEN从内部检索我想要的版本。 (< - 措辞不佳)。
也许有人可以给我一些关于这种方式的见解以及在无法访问框架时该怎么做。
如果您和您的团队是PHP开发人员并且没有时间学习框架,我建议使用redbean redbeanphp.com/index.php快速简单的orm准备使用
ORM无法解决您的所有问题
在许多情况下,使用模型访问数据库很方便,但并非总是如此。您可能更好地保持ORM模型不受需要复杂查询和高性能的任务的影响。
正确使用ORM模式
ORM只是您可以在代码中使用的众多编码模式之一。
阅读本主题以了解更多信息什么是ORM,我在哪里可以了解更多信息?
您不应该将ORM视为隔离数据库访问的应用程序层。它只是一种以面向对象的方式操作数据的技术。
在每个流行的框架中,您将看到ORM是一个选项,而不是必需的层。
考虑您希望获取特定文件的所有版本的情况。使用方法getAllVersions创建类似FileVersionManager singleton的东西,它将通过fid执行JOIN查询。这里也可以是checkoutToVersion或getPreviousVersion。此方法可以返回一个或一组Version ORM模型。重要的是 - 这种方式在语义上更有意义,因此更容易阅读和理解其他程序员。
或者,如果您需要在每个文件更改上生成版本,您可以将此逻辑委托给类似Versionable行为或类似的东西。
我更喜欢将ORM视为某种应用程序域定义层。
所以,回答你的问题
如果您想要自己的ORM实现,那么不要太复杂。使用CRUD方法和模式定义为每个表创建单独的ORM模型。并使用其他模式执行复杂查询。
示例(应该实现Query.selectWhere以使示例正常工作):
/**
* @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);
附:在这里,您可以定义自己的Query实现,这应该适用于您的(任何)数据源
P.P.S.我还是建议你学习一些流行的框架(Yii2,Laravel,Symfony或其他任何框架),因为它是学习构建应用程序架构的最佳实践的好方法。
好的。 在这种情况下,查询结果将传递到类模型中,它将处理数据?
@Dimitri如果你看一下框架,那么你会发现ORM通常不会直接查询到DB。 通常这里是附加层(如Yii中的QueryBuilder),ORM只提供了一种使用DB模式的透明方式。 您想要将ORM构建为严格地超出SQL查询的层,您将很快发现自己陷入灵活性限制的陷阱 - ORM将成为您的"瘦身"并且您会讨厌它们并且想要执行 直接在任何地方构建SQL查询而不是使用ORM。
@Dimitri我已经更新了我的答案。 包含ORM说明主题的链接和建议代码结构的一些示例。 希望这可以帮助
优秀! 非常感谢您的投入!
@Dimitri,欢迎你。 很高兴为您服务