2016-07-16 7 views
1

データベーステーブルからデータにアクセスする方法がわかりません。私は、例えばYiiのようなこれを手助けするフレームワークが数多くあることを知っていますが、私はチーム内の他の人たちとの習熟時間と時間制限のためにそのルートを避けようとしています。PHPアプリケーションとORMでのデータアクセスレイヤーの構築

私はという名前のテーブルを持っていて、名前のリスト、日付のアップロード、ユーザーのアップロードなどを持っているとします。Versionsと呼ばれる別のテーブルがあります。つまり、ユーザーが同じファイルをアップロードすると、それを改訂版とみなします。

ファイル

fid | name | uploadDate 
1 | test | 2017-01-01 
2 | test2 | 2017-01-01 

私の最初に考えたのは、私がFilesコンストラクタでfidに投げると、その単一の取得となる各テーブル用のクラスを作成することでしたバージョン

vid | fid | user 
1 | 1  | a 
2 | 1  | b 

行と同様にVersionsの場合は、vidがコンストラクタに配置され、特定のバージョン。

しかし、これは、クラスごとに1つずつ、2つの別々のクエリがあることを意味します。だから私はおそらくそれらを1つに組み合わせることを考えていた。これは、Filesクラス内の1つのクエリ(LEFT JOINを使用)でファイル情報とバージョン情報を取得し、dbを照会してデータを処理するのではなく、Versionsクラスを使用してデータを処理することを意味します。

何らかの理由で、私はここで私を助けるためにJOINSを使用しているので、より良いパフォーマンスが得られるように感じますが、一方、特定のバージョンのファイルについて情報が必要な場合は、 Fileのインスタンスを作成します。つまり、fidを使用して、そこから取得したいバージョンを取得します。 (< - 言葉が不十分です)。

おそらく誰かが私にこのやり方を少し洞察し、フレームワークにアクセスできないときに何をすべきかを教えてくれます。

+0

あなたとあなたのチームがPHP開発者であり、フレームワークを学ぶ時間がある、私はredbean http://www.redbeanphp.com/index.phpを使うことを提案します。速くて簡単なormを使う準備ができました。 –

答えて

1

ORMは、常にDBへのアクセスではなくするためにモデルを使用するのが便利である多くの場合、すべてのあなたの問題

を解決することはできません。複雑なクエリや高性能が必要な作業をORMモデルに任せておく方がよいでしょう。

使用ORMパターンが正しく

ORMはただ一つ、あなたのコード内で使用することができ、多くのコーディングパターンのです。

あなたは、データベースへのアクセスを隔離し、アプリケーション層としてのORMを検討するべきではありませんそれについてWhat is an ORM and where can I learn more about it?

の多くを学ぶために、このトピックをお読みください。これは、オブジェクト指向の方法でデータを操作する単なる技法です。

すべての一般的なフレームワークで、ORMはオプションであり、必須のレイヤではありません。

特定のファイルのすべてのバージョンを取得する場合を考えてみましょう。メソッドgetAllVersionsFileVersionManagerシングルトンのようなものを作成し、fidでJOINクエリを実行します。ここにはcheckoutToVersiongetPreviousVersionのようなものもあります。このメソッドは、Version ORMモデルの1つまたは複数を返すことができます。そして重要なことは、このように意味的に意味があり、したがって他のプログラマーが読んで理解しやすくなります。

また、各ファイルのバージョンを変更する必要がある場合は、このロジックを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など)を学ぶことをお勧めします。

+0

いいえ。この場合、クエリ結果はデー​​タを処理するクラスモデルに渡されますか? – Dimitri

+0

@Dimitriフレームワークを見れば、ORMは通常DBへの直接クエリをカプセル化しないことがわかります。ここでは通常、このための追加レイヤーがあります(YiiのQueryBuilderなど).ORMは、DBスキーマを操作するための透過的な方法を提供します。厳密にSQLクエリの上にあるレイヤーとしてORMを構築したい場合は、柔軟性限界のトラップに素早く乗ります - ORMはあなたの「薄い場所」になり、あなたはそれらを嫌い、実行したいORMを使用する代わりに、あらゆる場所にSQLクエリを直接作成できます。 – oakymax

+1

@Dimitri私は自分の答えを更新しました。 ORMの説明付きのトピックへのリンクと提案されたコード構造の小さな例が含まれています。これが役に立ったらいいですか – oakymax

関連する問題