design patterns - ¿Qué es un Proxy en Doctrine 2?
design-patterns doctrine2 (2)
Proxies
Un proxy de Doctrine es simplemente un contenedor que extiende una clase de entidad para proporcionarle la Carga diferida.
De forma predeterminada, cuando le pregunta al administrador de la entidad por una entidad que está asociada con otra entidad, la entidad asociada no se cargará desde la base de datos, sino que se integrará en un objeto proxy. Cuando su aplicación luego solicita una propiedad o llama a un método de esta entidad proxy, Doctrine cargará la entidad desde la base de datos (excepto cuando solicite la ID, que el proxy conoce siempre).
Esto sucede completamente transparente para su aplicación debido al hecho de que el proxy amplía su clase de entidad.
Doctrine hidratará de forma predeterminada las asociaciones como proxies de carga lenta si no los JOIN
en su consulta o establece el modo de búsqueda en EAGER
.
Ahora debo agregar esto porque no tengo suficiente reputación para comentar en todas partes:
Desafortunadamente, la respuesta de Crozin contiene información errónea.
Si ejecuta una consulta DQL como
SELECT u.id, u.username FROM Entity/User u WHERE u.id = :id
no obtendrá un objeto de entidad (proxy), sino una matriz asociativa. Por lo tanto, no es posible cargar cargas perezosas en propiedades adicionales.
Con esto en mente, se llega a la conclusión de que el ejemplo de caso de uso tampoco funcionará. El DQL tendría que cambiarse a algo como esto para acceder a $article
como objeto:
SELECT a FROM Entity/Article a ORDER BY a.createdAt DESC LIMIT 25
Y la propiedad devuelta por getContent()
debería ser una asociación para no cargar las propiedades de contenido de las 25 entidades.
Objetos parciales
Si desea cargar parcialmente las propiedades de entidad que no son asociaciones, debe contar esta Doctrina explícitamente:
SELECT partial u.{id, username} FROM Entity/User u WHERE u.id = :id
Esto le proporciona un objeto de entidad parcialmente cargado.
¡Pero ten en cuenta que los objetos parciales no son proxies! Lazy La carga no se aplica a ellos. Por lo tanto, el uso de objetos parciales es generalmente peligroso y debe evitarse. Leer más: Objetos parciales : documentación de Doctrine 2 ORM 2
Acabo de terminar de leer toda la documentación de Doctrine 2, comencé mi propia caja de arena, entendí la mayoría de los principios, pero todavía hay una pregunta y no pude encontrar ninguna explicación completa en el documento.
- ¿Qué son las clases
Proxy
? - ¿Cuándo debería usarlos sobre las entidades?
Por lo que yo entiendo, las clases proxy añaden una capa que te permite agregar algunas otras características a tus entidades, pero ¿por qué usar un proxy en lugar de implementar los métodos ellos mismos en la clase de entidad?
Los objetos proxy se utilizan siempre que su consulta no devuelva todos los datos necesarios para crear una entidad. Imagina el siguiente escenario:
@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
Como puede ver, esta consulta no devuelve las propiedades firstname
y lastname
, por lo tanto, no puede crear un objeto User
. La creación de una entidad incompleta podría generar errores inesperados.
Es por eso que Doctrine creará el objeto UserProxy
que admite la carga diferida. Cuando intente acceder a la propiedad firstname
(que no está cargada), primero cargará ese valor de la base de datos.
Quiero decir, ¿por qué debería usar un proxy?
Siempre debe escribir su código como si no usara objetos proxy en absoluto. Se pueden tratar como objetos internos utilizados por Doctrine.
¿Por qué la carga diferida no puede implementarse en la Entidad misma?
Técnicamente podría ser, pero eche un vistazo a la clase de algún objeto proxy al azar. Está lleno de código sucio, ugh. Es bueno tener un código limpio en tus entidades.
¿Me puede dar un caso de uso?
Está mostrando una lista de los últimos 25 artículos y desea mostrar los detalles de la primera. Cada uno de ellos contiene una gran cantidad de texto, por lo que recuperar todos esos datos sería una pérdida de memoria. Es por eso que no se obtienen datos innecesarios.
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;
}
}
ACTUALIZAR
En la sección de comentarios a continuación, hay información incorrecta sobre las diferencias entre los objetos proxy y los objetos parciales. Consulte las respuestas de @Kontrollfreak para obtener más detalles: https://.com/a/17787070/252591