Apa itu Proxy dalam Ajaran 2?

112

Saya baru saja selesai membaca semua dokumentasi Doktrin 2, saya memulai sandbox saya sendiri, saya memahami sebagian besar prinsip, tetapi masih ada pertanyaan dan saya tidak dapat menemukan penjelasan lengkap di dok.

  1. Apakah Proxykelas itu?
  2. Kapan saya harus menggunakannya untuk entitas?

Sejauh yang saya mengerti, kelas proxy menambahkan lapisan untuk memungkinkan Anda menambahkan beberapa fitur lain ke entitas Anda, tetapi mengapa menggunakan proxy daripada menerapkan metode itu sendiri di kelas entitas?

Jérémy
sumber

Jawaban:

160

MEMPERBARUI

Jawaban ini mengandung informasi yang salah tentang perbedaan antara objek proxy dan objek parsial. Lihat jawaban @ Kontrollfreak untuk lebih jelasnya: https://stackoverflow.com/a/17787070/252591


Objek proxy digunakan setiap kali kueri Anda tidak mengembalikan semua data yang diperlukan untuk membuat entitas. Bayangkan skenario berikut:

@Entity
class User {
     @Column protected $id;
     @Column protected $username;
     @Column protected $firstname;
     @Column protected $lastname;

     // bunch of setters/getters here
}

DQL query:

SELECT u.id, u.username FROM Entity\User u WHERE u.id = :id

Seperti yang Anda lihat, kueri ini tidak mengembalikan firstnamedan lastnameproperti, oleh karena itu Anda tidak dapat membuat Userobjek. Pembuatan entitas yang tidak lengkap dapat menyebabkan kesalahan yang tidak terduga.

Itu sebabnya Doctrine akan membuat UserProxyobjek yang mendukung lazy loading. Ketika Anda mencoba mengakses firstnameproperti (yang tidak dimuat), pertama-tama akan memuat nilai itu dari database.


Maksud saya, mengapa saya harus menggunakan proxy?

Anda harus selalu menulis kode Anda seolah-olah Anda tidak menggunakan objek proxy sama sekali. Mereka dapat diperlakukan sebagai objek internal yang digunakan oleh Doktrin.

Mengapa pemuatan lambat tidak dapat diterapkan di Entitiy itu sendiri?

Secara teknis bisa jadi tapi lihatlah kelas beberapa objek proxy acak. Itu penuh dengan kode kotor, ugh. Sangat menyenangkan memiliki kode yang bersih di entitas Anda.

Bisakah Anda memberi saya kasus penggunaan?

Anda sedang menampilkan daftar 25 artikel terbaru dan Anda ingin menampilkan rincian artikel pertama. Masing-masing berisi teks dalam jumlah besar, jadi mengambil semua data itu akan membuang-buang memori. Itulah mengapa Anda tidak mengambil data yang tidak perlu.

SELECT a.title, a.createdAt
FROM Entity\Article a
ORDER BY a.createdAt DESC
LIMIT 25

$isFirst = true;
foreach ($articles as $article) {
    echo $article->getTitle();
    echo $article->getCreatedAt();

    if ($isFirst) {
        echo $article->getContent(); // Article::content is not loaded so it is transparently loaded 
                                     // for this single article.

        $isFirst = false;
    }
}
Crozin
sumber
Terima kasih atas jawabannya, apa bedanya dengan Partial Object? Maksud saya, mengapa saya harus menggunakan proxy? Mengapa pemuatan lambat tidak dapat diterapkan di Entitiy itu sendiri? Bisakah Anda memberi saya kasus penggunaan?
Jérémy
1
Objek parsial dan objek proxy adalah hal yang sama - mereka dapat diperlakukan sebagai sinonim. Adapun pertanyaan lainnya, periksa jawaban saya yang diperbarui.
Crozin
1
Saya tidak mengerti mengapa doktrin tidak dapat membuat objek jika hanya memiliki setengah dari properti. Dalam php saya dapat membuat objek meskipun saya tidak mengatur semua properti.
sanders
1
Ini adalah jawaban yang sangat luar biasa dan harus ada dalam dokumentasi.
Jimbo
7
Jawaban ini mengandung beberapa kesalahpahaman yang serius tentang proxy dan objek parsial. Lihat jawaban saya untuk memahami mengapa.
Kontrollfreak
81

Proksi

Doctrine proxy hanyalah pembungkus yang memperluas kelas entitas untuk menyediakan Lazy Loading untuknya.

Secara default, saat Anda meminta Manajer Entitas untuk entitas yang terkait dengan entitas lain, entitas terkait tidak akan dimuat dari database, tetapi dibungkus ke dalam objek proxy. Ketika aplikasi Anda kemudian meminta properti atau memanggil metode entitas yang di-proxy ini, Doctrine akan memuat entitas dari database (kecuali jika Anda meminta ID, yang selalu dikenal oleh proxy).

Ini terjadi sepenuhnya transparan untuk aplikasi Anda karena fakta bahwa proxy memperluas kelas entitas Anda.

Doctrine secara default akan menghidrasi asosiasi sebagai proxy pemuatan lambat jika Anda tidak JOINmemasukkannya dalam kueri atau menyetel mode pengambilan ke EAGER.


Sekarang saya harus menambahkan ini karena saya tidak memiliki reputasi yang cukup untuk berkomentar di mana-mana:

Sayangnya, jawaban Crozin mengandung informasi yang salah.

Jika Anda menjalankan kueri DQL seperti

SELECT u.id, u.username FROM Entity\User u WHERE u.id = :id

Anda tidak akan mendapatkan objek entitas (yang diproksikan), tetapi array asosiatif. Jadi, tidak mungkin untuk memuat properti tambahan secara lambat.

Dengan pemikiran ini, seseorang sampai pada kesimpulan bahwa contoh use case juga tidak akan berfungsi. DQL harus diubah menjadi seperti ini untuk mengakses $articlesebagai objek:

SELECT a FROM Entity\Article a ORDER BY a.createdAt DESC LIMIT 25

Dan properti yang dikembalikan oleh getContent()harus berupa asosiasi agar tidak memuat properti konten dari semua 25 entitas.


Objek Parsial

Jika Anda ingin memuat sebagian properti entitas yang bukan merupakan asosiasi, Anda harus memberi tahu Doktrin ini secara eksplisit:

SELECT partial u.{id, username} FROM Entity\User u WHERE u.id = :id

Ini memberi Anda objek entitas yang dimuat sebagian.

Namun berhati-hatilah karena objek parsial bukanlah proxy! Lazy Loading tidak berlaku untuk mereka. Oleh karena itu, menggunakan objek parsial umumnya berbahaya dan harus dihindari. Baca lebih lanjut: Objek Parsial - Doktrin 2 ORM 2 dokumentasi

Kontrollfreak
sumber
1
Terima kasih, ini memberikan lebih banyak detail tentang bagaimana Doktrin menggunakan Proksi dan Objek Sebagian daripada jawaban yang diterima! Dan referensi ke dokumen juga membantu.
Sean the Bean
1
Juga untuk referensi, inilah bagian dari dokumen tentang objek Proxy: doktrin-orm.readthedocs.org/en/latest/reference/…
Sean the Bean
Jadi saat melakukan eager load, apakah pada dasarnya hanya menambahkan kumpulan hasil?