Pertanyaan Mendapatkan objek "benar" dari objek proxy dalam doktrin2


Doktrin menggunakan objek proxy untuk merepresentasikan objek terkait untuk memfasilitasi pemuatan yang malas. Ini adalah fitur yang sangat keren, tetapi menyebabkan masalah dengan sesuatu yang ingin saya capai.

Saya telah mengkustomisasi objek pengguna saya sehingga semuanya harus terkait dengan objek yang berbeda, yang akan saya sebut kota. Hubungan ini berfungsi dengan baik.

Saya memiliki formulir yang diisi oleh pengguna saya untuk menghasilkan objek lain, jalan. Jalan juga terkait dengan objek kota. Alih-alih meminta pengguna saya memilih kota ketika mereka mengisi formulir, saya ingin secara otomatis mengaturnya sebelum saya mempertahankan objek ke database saya.

Saya mencoba menggunakan $event->setCity($user->getCity()), tetapi karena $ user-> getCity () mengembalikan objek proxy, ini menghasilkan kesalahan. Apakah ada fungsi yang dapat saya hubungi dari objek proxy untuk mendapatkan yang asli?

Catatan: Saya sadar saya dapat membuat kueri khusus dengan gabungan untuk memaksa doktrin untuk benar-benar memuat objek terkait, tetapi karena ini adalah pengguna (menggunakan FOSUserBundle) yang akan sulit dilakukan dengan benar.


32
2017-12-01 07:14


asal


Jawaban:


Edit:  Seperti yang disebutkan oleh @flu pendekatan ini tidak mengembalikan objek yang "benar". Namun itu bisa berguna jika Anda memerlukan data dari objek. Kemudian, Anda bisa mendapatkan objek nyata dari ObjectManager oleh beberapa identitas.


Kita bisa menggunakan metode __load () dari antarmuka Proxy

$proxyObject->__load();

11
2017-07-01 03:23



Ini tidak mungkin membantu dalam contoh spesifik untuk pertanyaan, karena Anda mengandalkan modul pihak ketiga, tetapi Anda dapat mencegah pemuatan malas dengan mengatur "mode ambil" untuk entitas Anda ke "EAGER".

User:
    ManyToOne:
        city:
            fetch: EAGER

Ini juga dapat ditangani dengan anotasi:

@ManyToOne(targetEntity="city", fetch="EAGER")
@JoinColumn(name="city", referencedColumnName="id")

Lihat http://docs.doctrine-project.org/projects/doctrine-orm/en/latest/reference/annotations-reference.html#annref-manytoone

Tak satu pun dari jawaban lain yang pernah saya lihat di sini berhasil bagi saya.


11
2017-12-23 02:01



Inilah solusi saya:

Konteks:

Semua entitas saya miliki id properti dan getId() metode


Larutan:

$em = $this->getDoctrine()->getManager();

// 1 -> get the proxy object class name
$proxy_class_name = get_class($proxyObject);

// 2 -> get the real object class name
$class_name = $em->getClassMetadata($proxy_class_name)->rootEntityName;

// 3 -> get the real object
$object = $em->find($class_name, $proxyObject->getId());

Masalah:

Solusi ini tidak berfungsi jika id properti dan getId() metode berada dalam Trait kelas

Saya berharap itu dapat membantu seseorang


2
2017-09-30 15:59



Anda mendapatkan contoh unik dari entitas dari Ajaran. Jika Anda memintanya dua kali, Anda akan selalu mendapatkan objek yang sama.

Sebagai akibatnya, jika entitas Anda bermalas-malasan terlebih dahulu (via @ManyToOne di suatu tempat misalnya), instance entitas ini akan menjadi Proxy.

Contoh:

Anda memiliki entitas Pengguna yang memiliki dua arah @OneToOne pada entitas Config ...

Kasus 1

Anda meminta Pengguna Anda:

  • kamu mendapatkan nyata contoh Pengguna
  • $ user-> config akan berisi Proxy

Jika nantinya Anda meminta entitas Config yang sama di setiap bagian aplikasi Anda, Anda akan berakhir dengan proxy tersebut.

Kasus 2

Anda meminta Konfigurasi Anda dan Pengguna Anda belum pernah diimpor sebelumnya:

  • kamu mendapatkan nyata contoh Config
  • $ config-> user akan berisi Proxy

Jika nantinya Anda meminta entitas Pengguna yang sama di bagian mana saja dari aplikasi Anda, Anda akan berakhir dengan proxy tersebut.


Semua dalam semua, query lagi untuk entitas yang sama akan tetap berakhir ke proxy (yang merupakan contoh dari Pengguna Anda pula, karena proxy yang dihasilkan meluas dari itu).

Jika kamu sangat perlu contoh kedua dari entitas Anda yang merupakan a real satu (jika beberapa logika aplikasi Anda melakukan a get_class yang tidak bisa Anda ganti instanceof misalnya), Anda dapat mencoba bermain dengan $em->detach() tetapi itu akan menjadi mimpi buruk (dan dengan demikian aplikasi Anda mungkin berperilaku dengan lebih banyak keajaiban daripada yang sudah dibawa oleh Doktrin).

Solusi (datang dari sisi gelap saya, saya berasumsi) dapat menciptakan Entitas yang dikelola secara manual.

public function getRealEntity($proxy)
{
    if ($proxy instanceof Doctrine\ORM\Proxy\Proxy) {
        $metadata              = $this->getManager()->getMetadataFactory()->getMetadataFor(get_class($proxy));
        $class                 = $metadata->getName();
        $entity                = new $class();
        $reflectionSourceClass = new \ReflectionClass($proxy);
        $reflectionTargetClass = new \ReflectionClass($entity);
        foreach ($metadata->getFieldNames() as $fieldName) {
            $reflectionPropertySource = $reflectionSourceClass->getProperty($fieldName);
            $reflectionPropertySource->setAccessible(true);
            $reflectionPropertyTarget = $reflectionTargetClass->getProperty($fieldName);
            $reflectionPropertyTarget->setAccessible(true);
            $reflectionPropertyTarget->setValue($entity, $reflectionPropertySource->getValue($proxy));
        }

        return $entity;
    }

    return $proxy;
}

1
2018-01-31 07:19



Ini adalah sedikit solusi jahat yang bermasalah:

// $proxyObject = ...

$em->detach($proxyObject);
$entityObject = $em->find(<ENTITY_CLASS>, $proxyObject->getId());

// now you have real entity and not the proxy (entityObject instead of proxyObject)

setelah itu Anda dapat mengganti referensi proxy jika Anda perlu memilikinya di dalam entitas lain


1
2018-04-21 09:34



Doktrin pemuatan malas sangat bagus dalam pekerjaannya, dan akan menggantikan objek proxy dengan yang asli segera setelah Anda mencoba menggunakannya atau salah satu propertinya. Jika Anda mengalami masalah karena objek proxy (seperti yang saya lakukan dalam pertanyaan saya), Anda kemungkinan besar memiliki kesalahan dalam model Anda.

Yang mengatakan, Anda dapat memberi tahu doktrin untuk menarik semua data terkait dengan mengatakannya untuk "melembabkan": $query->getResult(Doctrine\ORM\Query::HYDRATE_ARRAY);


0
2018-04-15 13:26



Ini akan mengonversi referensi ke objek nyata dan mengambil semua bidang.

$entityManager->refresh($proxyObject);

-3
2018-05-05 16:50