Bagaimana seharusnya model disusun dalam MVC? [Tutup]

551

Saya hanya mendapatkan pemahaman tentang kerangka kerja MVC dan saya sering bertanya-tanya berapa banyak kode yang harus dimasukkan dalam model. Saya cenderung memiliki kelas akses data yang memiliki metode seperti ini:

public function CheckUsername($connection, $username)
{
    try
    {
        $data = array();
        $data['Username'] = $username;

        //// SQL
        $sql = "SELECT Username FROM" . $this->usersTableName . " WHERE Username = :Username";

        //// Execute statement
        return $this->ExecuteObject($connection, $sql, $data);
    }
    catch(Exception $e)
    {
        throw $e;
    }
}

Model saya cenderung kelas entitas yang dipetakan ke tabel database.

Haruskah objek model memiliki semua properti database yang dipetakan serta kode di atas atau apakah OK untuk memisahkan kode yang sebenarnya berfungsi sebagai basis data?

Apakah saya akan memiliki empat lapisan?

Dietpixel
sumber
133
Mengapa Anda menangkap pengecualian hanya untuk melemparkannya lagi?
Bailey Parker
9
@Elias Van Ootegem: Anda melewatkan intinya. tidak ada gunanya menangkap mereka dalam kasus ini.
Karoly Horvath
4
@Elias Van Ootegem: ya? jika ia bekerja dengan rethrow, itu berarti bahwa lapisan atas menangkap pengecualian. Tetapi jika ada satu, maka itu akan menangkapnya tanpa menggunakan kembali yang tidak ada gunanya ... (jika Anda masih belum mendapatkannya, tolong tirukan kode uji kecil)
Karoly Horvath
3
@ Elias Van Ootegem: Saya tidak tahu apa yang Anda bicarakan, tidak menangani pengecualian pada lapisan tertentu tidak berarti itu akan menghentikan aplikasi. tolong buat (atau lebih tepatnya: gagal membangun) contoh kode di mana rethrow diperlukan. mari kita hentikan percakapan offtopik ini, tolong
Karoly Horvath
6
@drrcknlsn: itu argumen yang valid, tetapi dalam kasus itu setidaknya menangkap pengecualian yang Anda harapkan untuk dibuang, generik Exceptiontidak memiliki banyak nilai dokumentasi. Secara pribadi jika saya turun di jalan itu saya akan memilih PHPDoc @exception, atau mekanisme serupa, sehingga muncul di dokumentasi yang dihasilkan.
Karoly Horvath

Jawaban:

903

Penafian: berikut ini adalah deskripsi bagaimana saya memahami pola mirip MVC dalam konteks aplikasi web berbasis PHP. Semua tautan eksternal yang digunakan dalam konten ada di sana untuk menjelaskan istilah dan konsep, dan tidak menyiratkan kredibilitas saya sendiri pada subjek.

Hal pertama yang harus saya jelaskan adalah: modelnya adalah layer .

Kedua: ada perbedaan antara MVC klasik dan apa yang kami gunakan dalam pengembangan web. Inilah sedikit jawaban lama yang saya tulis, yang menjelaskan secara singkat bagaimana perbedaannya.

Apa yang BUKAN model:

Model ini bukan kelas atau objek apa pun. Ini adalah kesalahan yang sangat umum terjadi (saya juga melakukannya, meskipun jawaban aslinya ditulis ketika saya mulai belajar sebaliknya) , karena sebagian besar kerangka kerja melanggengkan kesalahpahaman ini.

Baik itu teknik Pemetaan Objek-Relasional (ORM) maupun abstraksi tabel database. Siapa pun yang memberi tahu Anda sebaliknya kemungkinan besar akan berusaha 'menjual' ORM baru atau seluruh kerangka kerja.

Apa itu model:

Dalam adaptasi MVC tepat, M berisi semua logika bisnis domain dan lapisan Model yang sebagian besar terbuat dari tiga jenis struktur:

  • Objek Domain

    Objek domain adalah wadah logis dari informasi domain murni; biasanya mewakili entitas logis dalam ruang domain masalah. Biasa disebut sebagai logika bisnis .

    Ini adalah tempat Anda menentukan cara memvalidasi data sebelum mengirim faktur, atau menghitung total biaya pesanan. Pada saat yang sama, Objek Domain benar-benar tidak menyadari penyimpanan - baik dari mana (database SQL, REST API, file teks, dll.) Atau bahkan jika mereka disimpan atau diambil.

  • Pemetaan Data

    Objek-objek ini hanya bertanggung jawab atas penyimpanan. Jika Anda menyimpan informasi dalam database, ini akan menjadi tempat tinggal SQL. Atau mungkin Anda menggunakan file XML untuk menyimpan data, dan Pemeta Data Anda menguraikan dari dan ke file XML.

  • Jasa

    Anda dapat menganggapnya sebagai "Objek Domain tingkat tinggi", tetapi alih-alih logika bisnis, Layanan bertanggung jawab atas interaksi antara Objek Domain dan Pemetaan . Struktur ini pada akhirnya menciptakan antarmuka "publik" untuk berinteraksi dengan logika bisnis domain. Anda dapat menghindarinya, tetapi dengan membocorkan beberapa logika domain ke Controllers .

    Ada jawaban terkait untuk subjek ini dalam pertanyaan implementasi ACL - mungkin berguna.

Komunikasi antara lapisan model dan bagian lain dari triad MVC harus terjadi hanya melalui Layanan . Pemisahan yang jelas memiliki beberapa manfaat tambahan:

  • membantu menegakkan prinsip tanggung jawab tunggal (SRP)
  • menyediakan 'ruang gerak' tambahan jika terjadi perubahan logika
  • membuat pengontrol sesederhana mungkin
  • memberikan cetak biru yang jelas, jika Anda membutuhkan API eksternal

 

Bagaimana cara berinteraksi dengan model?

Prasyarat: menonton kuliah "Global State and Singletons" dan "Don't Look Things!" dari Pembicaraan Kode Bersih.

Mendapatkan akses ke instance layanan

Agar instance View dan Controller (apa yang bisa Anda sebut: "lapisan UI") untuk mengakses layanan ini, ada dua pendekatan umum:

  1. Anda dapat menyuntikkan layanan yang diperlukan dalam konstruktor pandangan dan pengontrol Anda secara langsung, lebih disukai menggunakan wadah DI.
  2. Menggunakan pabrik untuk layanan sebagai ketergantungan wajib untuk semua pandangan dan pengontrol Anda.

Seperti yang Anda duga, wadah DI adalah solusi yang jauh lebih elegan (meskipun bukan yang paling mudah bagi pemula). Kedua pustaka, yang saya rekomendasikan mempertimbangkan fungsi ini akan menjadi komponen mandiri DependencyInjection atau Auryn milik Syfmony .

Baik solusi menggunakan pabrik dan wadah DI akan memungkinkan Anda juga berbagi contoh berbagai server untuk dibagikan antara pengontrol yang dipilih dan melihat siklus permintaan-respons yang diberikan.

Perubahan status model

Sekarang Anda dapat mengakses ke lapisan model di pengontrol, Anda harus mulai benar-benar menggunakannya:

public function postLogin(Request $request)
{
    $email = $request->get('email');
    $identity = $this->identification->findIdentityByEmailAddress($email);
    $this->identification->loginWithPassword(
        $identity,
        $request->get('password')
    );
}

Pengontrol Anda memiliki tugas yang sangat jelas: ambil input pengguna dan, berdasarkan input ini, ubah status logika bisnis saat ini. Dalam contoh ini negara yang diubah antara adalah "pengguna anonim" dan "pengguna masuk".

Pengontrol tidak bertanggung jawab untuk memvalidasi input pengguna, karena itu adalah bagian dari aturan bisnis dan pengontrol jelas tidak memanggil permintaan SQL, seperti apa yang akan Anda lihat di sini atau di sini (jangan membenci mereka, mereka salah arah, bukan jahat).

Menampilkan pengguna perubahan-negara.

Oke, pengguna telah login (atau gagal). Sekarang apa? Kata pengguna masih tidak menyadarinya. Jadi, Anda harus benar-benar menghasilkan respons dan itu adalah tanggung jawab pandangan.

public function postLogin()
{
    $path = '/login';
    if ($this->identification->isUserLoggedIn()) {
        $path = '/dashboard';
    }
    return new RedirectResponse($path); 
}

Dalam kasus ini, tampilan menghasilkan salah satu dari dua kemungkinan respons, berdasarkan kondisi lapisan model saat ini. Untuk kasus penggunaan yang berbeda, Anda akan memiliki pandangan memilih template yang berbeda untuk di-render, berdasarkan sesuatu seperti "artikel yang dipilih saat ini".

Lapisan presentasi sebenarnya bisa sangat rumit, seperti dijelaskan di sini: Memahami Tampilan MVC di PHP .

Tapi saya hanya membuat API REST!

Tentu saja, ada beberapa situasi, ketika ini adalah pembunuhan yang berlebihan.

MVC hanyalah solusi konkret untuk prinsip Pemisahan Kekhawatiran . MVC memisahkan antarmuka pengguna dari logika bisnis, dan di UI memisahkan pemisahan input pengguna dan presentasi. Ini sangat penting. Walaupun sering orang menggambarkannya sebagai "triad", itu sebenarnya tidak terdiri dari tiga bagian independen. Strukturnya lebih seperti ini:

Pemisahan MVC

Ini berarti, bahwa, ketika logika lapisan presentasi Anda hampir tidak ada, pendekatan pragmatis adalah menjaganya sebagai lapisan tunggal. Itu juga secara substansial dapat menyederhanakan beberapa aspek lapisan model.

Menggunakan pendekatan ini contoh login (untuk API) dapat ditulis sebagai:

public function postLogin(Request $request)
{
    $email = $request->get('email');
    $data = [
        'status' => 'ok',
    ];
    try {
        $identity = $this->identification->findIdentityByEmailAddress($email);
        $token = $this->identification->loginWithPassword(
            $identity,
            $request->get('password')
        );
    } catch (FailedIdentification $exception) {
        $data = [
            'status' => 'error',
            'message' => 'Login failed!',
        ]
    }

    return new JsonResponse($data);
}

Meskipun ini tidak berkelanjutan, ketika Anda memiliki logika yang rumit untuk merender badan respons, penyederhanaan ini sangat berguna untuk skenario yang lebih sepele. Tetapi berhati-hatilah , pendekatan ini akan menjadi mimpi buruk, ketika mencoba untuk digunakan dalam basis kode besar dengan logika presentasi yang kompleks.

 

Bagaimana cara membangun model?

Karena tidak ada satu kelas "Model" (seperti dijelaskan di atas), Anda benar-benar tidak "membangun model". Alih-alih, Anda mulai membuat Layanan , yang dapat melakukan metode tertentu. Dan kemudian mengimplementasikan Objek Domain dan Pemetaan .

Contoh metode layanan:

Dalam kedua pendekatan di atas ada metode login ini untuk layanan identifikasi. Seperti apa bentuknya sebenarnya. Saya menggunakan versi yang sedikit dimodifikasi dari fungsi yang sama dari perpustakaan , yang saya tulis .. karena saya malas:

public function loginWithPassword(Identity $identity, string $password): string
{
    if ($identity->matchPassword($password) === false) {
        $this->logWrongPasswordNotice($identity, [
            'email' => $identity->getEmailAddress(),
            'key' => $password, // this is the wrong password
        ]);

        throw new PasswordMismatch;
    }

    $identity->setPassword($password);
    $this->updateIdentityOnUse($identity);
    $cookie = $this->createCookieIdentity($identity);

    $this->logger->info('login successful', [
        'input' => [
            'email' => $identity->getEmailAddress(),
        ],
        'user' => [
            'account' => $identity->getAccountId(),
            'identity' => $identity->getId(),
        ],
    ]);

    return $cookie->getToken();
}

Seperti yang Anda lihat, pada tingkat abstraksi ini, tidak ada indikasi dari mana data itu diambil. Mungkin database, tetapi juga mungkin hanya obyek tiruan untuk tujuan pengujian. Bahkan pemetaan data, yang sebenarnya digunakan untuk itu, disembunyikan dalam privatemetode layanan ini.

private function changeIdentityStatus(Entity\Identity $identity, int $status)
{
    $identity->setStatus($status);
    $identity->setLastUsed(time());
    $mapper = $this->mapperFactory->create(Mapper\Identity::class);
    $mapper->store($identity);
}

Cara membuat pemetaan

Untuk mengimplementasikan abstraksi kegigihan, pendekatan yang paling fleksibel adalah membuat pemetaan data khusus .

Diagram mapper

Dari: PoEAA Buku

Dalam praktiknya mereka diimplementasikan untuk interaksi dengan kelas atau superclasses tertentu. Katakanlah Anda memiliki Customerdan Admindalam kode Anda (keduanya mewarisi dari Usersuperclass). Keduanya mungkin akhirnya memiliki mapper yang cocok dan terpisah, karena mengandung bidang yang berbeda. Tetapi Anda juga akan berakhir dengan operasi bersama dan umum digunakan. Misalnya: memperbarui "yang terakhir terlihat online" . Dan alih-alih membuat pemetaan yang ada menjadi lebih berbelit-belit, pendekatan yang lebih pragmatis adalah memiliki "Pengguna Mapper" umum, yang hanya memperbarui stempel waktu itu.

Beberapa komentar tambahan:

  1. Tabel dan model basis data

    Meskipun kadang-kadang ada hubungan langsung 1: 1: 1 antara tabel database, Domain Object , dan Mapper , dalam proyek yang lebih besar mungkin lebih jarang terjadi daripada yang Anda harapkan:

    • Informasi yang digunakan oleh objek Domain tunggal mungkin dipetakan dari tabel yang berbeda, sedangkan objek itu sendiri tidak memiliki kegigihan dalam database.

      Contoh: jika Anda menghasilkan laporan bulanan. Ini akan mengumpulkan informasi dari berbagai tabel, tetapi tidak ada MonthlyReporttabel ajaib dalam database.

    • Seorang Mapper tunggal dapat memengaruhi banyak tabel.

      Contoh: saat Anda menyimpan data dari Userobjek, Objek Domain ini dapat berisi kumpulan objek domain lainnya - Groupinstance. Jika Anda mengubahnya dan menyimpannya User, Data Mapper harus memperbarui dan / atau memasukkan entri dalam beberapa tabel.

    • Data dari Objek Domain tunggal disimpan di lebih dari satu tabel.

      Contoh: dalam sistem besar (pikirkan: jaringan sosial berukuran sedang), mungkin pragmatis untuk menyimpan data autentikasi pengguna dan data yang sering diakses secara terpisah dari potongan konten yang lebih besar, yang jarang diperlukan. Dalam hal ini Anda mungkin masih memiliki satu Userkelas, tetapi informasi yang dikandungnya akan bergantung pada apakah rincian lengkap diambil.

    • Untuk setiap Objek Domain, mungkin ada lebih dari satu mapper

      Contoh: Anda memiliki situs berita dengan basis kode bersama untuk perangkat lunak manajemen publik dan publik. Tapi, sementara kedua antarmuka menggunakan Articlekelas yang sama , manajemen membutuhkan lebih banyak info yang terisi di dalamnya. Dalam hal ini Anda akan memiliki dua pemetaan yang terpisah: "internal" dan "eksternal". Setiap melakukan kueri yang berbeda, atau bahkan menggunakan basis data yang berbeda (seperti pada master atau slave).

  2. Tampilan bukan templat

    Lihat contoh di MVC (jika Anda tidak menggunakan variasi pola MVP) bertanggung jawab untuk logika presentasi. Ini berarti bahwa setiap Tampilan biasanya akan menyulap setidaknya beberapa templat. Ia memperoleh data dari Model Layer dan kemudian, berdasarkan informasi yang diterima, memilih templat dan menetapkan nilai.

    Salah satu manfaat yang Anda peroleh dari hal ini adalah penggunaan kembali. Jika Anda membuat ListViewkelas, maka, dengan kode yang ditulis dengan baik, Anda dapat memiliki kelas yang sama menyerahkan presentasi daftar pengguna dan komentar di bawah artikel. Karena mereka berdua memiliki logika presentasi yang sama. Anda cukup mengganti templat.

    Anda bisa menggunakan templat PHP asli atau menggunakan mesin templating pihak ketiga. Mungkin juga ada beberapa perpustakaan pihak ketiga, yang dapat sepenuhnya menggantikan Lihat contoh.

  3. Bagaimana dengan versi lama dari jawabannya?

    Satu-satunya perubahan besar adalah bahwa, apa yang disebut Model dalam versi lama, sebenarnya adalah Layanan . Sisa dari "analogi perpustakaan" terus berjalan dengan baik.

    Satu-satunya kelemahan yang saya lihat adalah bahwa ini akan menjadi perpustakaan yang benar-benar aneh, karena itu akan mengembalikan Anda informasi dari buku itu, tetapi tidak membiarkan Anda menyentuh buku itu sendiri, karena kalau tidak abstraksi akan mulai "bocor". Saya mungkin harus memikirkan analogi yang lebih pas.

  4. Apa hubungan antara instance View dan Controller ?

    Struktur MVC terdiri dari dua lapisan: ui dan model. Struktur utama pada lapisan UI adalah view dan controller.

    Saat Anda berurusan dengan situs web yang menggunakan pola desain MVC, cara terbaik adalah memiliki hubungan 1: 1 antara tampilan dan pengontrol. Setiap tampilan mewakili seluruh halaman di situs web Anda dan memiliki pengontrol khusus untuk menangani semua permintaan yang masuk untuk tampilan tertentu.

    Misalnya, untuk mewakili artikel yang dibuka, Anda harus \Application\Controller\Documentdan \Application\View\Document. Ini akan berisi semua fungsi utama untuk lapisan UI, ketika berurusan dengan artikel (tentu saja Anda mungkin memiliki beberapa komponen XHR yang tidak terkait langsung dengan artikel) .

tereško
sumber
4
@Rinzler, Anda akan melihat, bahwa di mana pun di tautan itu, apa pun yang dikatakan tentang Model (kecuali dalam satu komentar). Ini hanya "antarmuka berorientasi objek ke tabel database" . Jika Anda mencoba untuk mencetak ini dalam model seperti, Anda akhirnya melanggar SRP dan LSP .
tereško
8
@hafichuk hanya situasi, ketika masuk akal untuk menggunakan pola ActiveRecord adalah untuk prototipe. Ketika Anda mulai menulis kode yang dimaksudkan untuk produksi, itu menjadi anti-pola, karena menggabungkan penyimpanan dan logika bisnis. Dan karena Model Layer sama sekali tidak mengetahui bagian MVC lainnya. Ini tidak berubah tergantung pada variasi pada pola asli . Bahkan saat menggunakan MVVM. Tidak ada "beberapa model" dan mereka tidak dipetakan ke apa pun. Model adalah layer.
tereško
3
Versi Pendek - Model adalah Struktur Data .
Eddie B
9
Yah melihat bahwa ia menemukan MVC artikel itu mungkin memiliki beberapa kelebihan.
Eddie B
3
... atau bahkan hanya satu set fungsi. MVC tidak perlu diimplementasikan dalam gaya OOP, meskipun sebagian besar diimplementasikan seperti itu. Yang paling penting adalah memisahkan layer dan menetapkan data yang tepat serta mengontrol aliran
hek2mgl
37

Segala sesuatu yang merupakan logika bisnis termasuk dalam model, apakah itu permintaan basis data, perhitungan, panggilan REST, dll.

Anda dapat memiliki akses data dalam model itu sendiri, pola MVC tidak membatasi Anda untuk melakukan itu. Anda dapat menambahkannya dengan layanan, pemetaan dan yang tidak, tetapi definisi sebenarnya dari sebuah model adalah lapisan yang menangani logika bisnis, tidak lebih, tidak kurang. Itu bisa berupa kelas, fungsi, atau modul lengkap dengan trilyun objek jika itu yang Anda inginkan.

Itu selalu lebih mudah untuk memiliki objek terpisah yang benar-benar mengeksekusi query database daripada mengeksekusi mereka dalam model secara langsung: ini akan sangat berguna ketika pengujian unit (karena kemudahan menyuntikkan ketergantungan database tiruan dalam model Anda):

class Database {
   protected $_conn;

   public function __construct($connection) {
       $this->_conn = $connection;
   }

   public function ExecuteObject($sql, $data) {
       // stuff
   }
}

abstract class Model {
   protected $_db;

   public function __construct(Database $db) {
       $this->_db = $db;
   }
}

class User extends Model {
   public function CheckUsername($username) {
       // ...
       $sql = "SELECT Username FROM" . $this->usersTableName . " WHERE ...";
       return $this->_db->ExecuteObject($sql, $data);
   }
}

$db = new Database($conn);
$model = new User($db);
$model->CheckUsername('foo');

Juga, dalam PHP, Anda jarang perlu menangkap / rethrow pengecualian karena backtrace dipertahankan, terutama dalam kasus seperti contoh Anda. Biarkan saja pengecualiannya dilempar dan tangkap di controller saja.

netcoder
sumber
Struktur saya sangat mirip, saya pikir saya hanya memisahkannya sedikit lebih banyak. Alasan mengapa saya melewati koneksi adalah karena saya perlu memiliki potongan berjalan dalam transaksi. Saya ingin menambahkan pengguna dan kemudian menambahkan pengguna ke peran, tetapi peran kembali jika ada yang gagal. Satu-satunya cara saya bisa mengatasinya adalah dengan melewatkan koneksi.
Dietpixel
10
-1: itu juga benar-benar salah. Model bukan abstraksi untuk tabel.
tereško
1
The Userclass pada dasarnya meluas model, tapi itsn't obyek. Pengguna harus menjadi objek dan memiliki properti seperti: id, nama ... Anda menyebarkan Userkelas adalah bantuan.
TomSawyer
1
Saya pikir Anda mengerti MVC tetapi tidak mengerti apa itu OOP. Dalam skenario ini, seperti yang saya katakan, Usersingkatan dari objek, dan itu harus memiliki properti Pengguna, bukan metode seperti CheckUsername, apa yang harus Anda lakukan jika Anda ingin membuat Userobjek baru ? new User($db)
TomSawyer
@ TomSawyer OOP tidak berarti objek diharuskan memiliki properti. Apa yang Anda gambarkan adalah pola desain, yang tidak relevan dengan pertanyaan atau jawaban untuk pertanyaan itu. OOP adalah model bahasa, bukan pola desain.
netcoder
20

Di Web- "MVC" Anda dapat melakukan apa saja sesuka Anda.

Konsep asli (1) menggambarkan model sebagai logika bisnis. Itu harus mewakili negara aplikasi dan menegakkan beberapa konsistensi data. Pendekatan itu sering digambarkan sebagai "model gemuk".

Sebagian besar kerangka kerja PHP mengikuti pendekatan yang lebih dangkal, di mana model hanyalah antarmuka basis data. Tetapi setidaknya model-model ini masih harus memvalidasi data yang masuk dan hubungan.

Either way, Anda tidak terlalu jauh jika Anda memisahkan hal-hal SQL atau panggilan basis data ke lapisan lain. Dengan cara ini Anda hanya perlu memusatkan perhatian pada data / perilaku nyata, bukan dengan API penyimpanan yang sebenarnya. (Namun tidak masuk akal untuk melakukannya secara berlebihan. Misalnya Anda tidak akan pernah bisa mengganti database backend dengan penyimpanan file jika itu tidak dirancang sebelumnya.)

mario
sumber
8
tautan tidak valid (404)
Kyslik
6

Lebih sering sebagian besar aplikasi akan memiliki data, tampilan dan bagian pemrosesan dan kami hanya memasukkan semua itu dalam surat M, Vdan C.

Model ( M) -> Memiliki atribut yang memiliki status aplikasi dan tidak tahu apa-apa tentang Vdan C.

Lihat ( V) -> Memiliki format tampilan untuk aplikasi dan dan hanya tahu tentang cara mencerna model di atasnya dan tidak peduli C.

Controller ( C) ----> Memproses bagian aplikasi dan bertindak sebagai kabel antara M dan V dan itu tergantung pada keduanya M, Vtidak seperti Mdan V.

Secara keseluruhan ada pemisahan perhatian di antara masing-masing. Di masa depan setiap perubahan atau peningkatan dapat ditambahkan dengan sangat mudah.

merasa baik dan pemrograman
sumber
0

Dalam kasus saya, saya memiliki kelas database yang menangani semua interaksi database langsung seperti permintaan, pengambilan, dan semacamnya. Jadi jika saya harus mengubah database saya dari MySQL ke PostgreSQL tidak akan ada masalah. Jadi menambahkan lapisan tambahan itu bisa bermanfaat.

Setiap tabel dapat memiliki kelas sendiri dan memiliki metode spesifik, tetapi untuk benar-benar mendapatkan data, itu memungkinkan kelas database menanganinya:

Mengajukan Database.php

class Database {
    private static $connection;
    private static $current_query;
    ...

    public static function query($sql) {
        if (!self::$connection){
            self::open_connection();
        }
        self::$current_query = $sql;
        $result = mysql_query($sql,self::$connection);

        if (!$result){
            self::close_connection();
            // throw custom error
            // The query failed for some reason. here is query :: self::$current_query
            $error = new Error(2,"There is an Error in the query.\n<b>Query:</b>\n{$sql}\n");
            $error->handleError();
        }
        return $result;
    }
 ....

    public static function find_by_sql($sql){
        if (!is_string($sql))
            return false;

        $result_set = self::query($sql);
        $obj_arr = array();
        while ($row = self::fetch_array($result_set))
        {
            $obj_arr[] = self::instantiate($row);
        }
        return $obj_arr;
    }
}

Tabel objek kelasL

class DomainPeer extends Database {

    public static function getDomainInfoList() {
        $sql = 'SELECT ';
        $sql .='d.`id`,';
        $sql .='d.`name`,';
        $sql .='d.`shortName`,';
        $sql .='d.`created_at`,';
        $sql .='d.`updated_at`,';
        $sql .='count(q.id) as queries ';
        $sql .='FROM `domains` d ';
        $sql .='LEFT JOIN queries q on q.domainId = d.id ';
        $sql .='GROUP BY d.id';
        return self::find_by_sql($sql);
    }

    ....
}

Saya harap contoh ini membantu Anda membuat struktur yang baik.

Ibu
sumber
12
"Jadi jika saya harus mengubah database saya dari MySQL ke PostgreSQL tidak akan ada masalah." Uhhhmmm dengan kode di atas Anda akan memiliki masalah besar mengubah imo apa pun.
PeeHaa
Saya melihat jawaban saya semakin tidak masuk akal setelah diedit, dan seiring berjalannya waktu. Tapi itu harus tetap di sini
Ibu
2
Databasedalam contoh ini bukan kelas. Itu hanya pembungkus untuk fungsi. Juga, bagaimana Anda bisa memiliki "kelas objek tabel" tanpa objek?
tereško
2
@ tereško Saya telah membaca banyak posting Anda dan sangat bagus. Tapi, saya tidak dapat menemukan kerangka kerja yang lengkap untuk dipelajari. Apakah Anda tahu satu yang "tidak benar"? Atau setidaknya satu yang tidak seperti Anda dan beberapa orang lain di sini pada SO katakan harus dilakukan? Terima kasih.
johnny
Saya mungkin terlambat, tetapi saya ingin menunjukkan bahwa PDO hampir menyelesaikan masalah harus membuat 'lapisan' DB untuk memfasilitasi perubahan di masa depan.
Matthew Goulart