Metodos de busqueda
Versión 1 (Guillermo Zdanowicz, 14/08/2013 01:14)
1 | 1 | Guillermo Zdanowicz | h1. Metodos de busqueda |
---|---|---|---|
2 | 1 | Guillermo Zdanowicz | |
3 | 1 | Guillermo Zdanowicz | Data Hydrators con Symfony 1.4 y Doctrine |
4 | 1 | Guillermo Zdanowicz | |
5 | 1 | Guillermo Zdanowicz | Rating: 5.0/5 (2 votes cast) |
6 | 1 | Guillermo Zdanowicz | Muchas veces busqué alguna buena documentación sobre los Data Hydrators de Doctrine más como ejemplos que simples explicaciones y luego de mucha pelea logré entenderlos bien como para trabajar a gusto con ellos por lo que me gustaría dejarlo por escrito por si pueda serles de utilidad. |
7 | 1 | Guillermo Zdanowicz | |
8 | 1 | Guillermo Zdanowicz | Me gustaría empezar con el concepto de que son los Data Hydrators haciendo referencia a la documentación oficial de Doctrine en su sitio web. |
9 | 1 | Guillermo Zdanowicz | |
10 | 1 | Guillermo Zdanowicz | Doctrine has a concept of data hydrators for transforming your Doctrine_Query instances to a set of PHP data for the user to take advantage of. The most obvious way to hydrate the data is to put it into your object graph and return models/class instances. Sometimes though you want to hydrate the data to an array, use no hydration or return a single scalar value. |
11 | 1 | Guillermo Zdanowicz | |
12 | 1 | Guillermo Zdanowicz | Yo lo explicaría diciendo que Doctrine utiliza Data Hydrators para la transformación de los Doctrine_Query que usamos al momento de hacer nuestros DQLs. Es decir, un DQL generado por nosotros nos sirve para generar dinámicamente el SQL necesario para ejecutarlo contra la base de datos y nos devuelve de alguna manera información de la base de datos que por lo general lo hubiésemos denominado un ResultSet. Estos datos devueltos vienen en un formato que Doctrine maneja y los Data Hydrators nos permiten decirle que nos devuelva de cierta manera que podamos manipularlos más fácilmente. A este proceso de transformación se le denomina “hidratar los datos” y nos sirve para manipularlos como objetos, arrays o como un valor único a lo que se le denomina valor escalar. |
13 | 1 | Guillermo Zdanowicz | |
14 | 1 | Guillermo Zdanowicz | Para los ejemplos podríamos tener las siguientes tablas: |
15 | 1 | Guillermo Zdanowicz | |
16 | 1 | Guillermo Zdanowicz | »config/doctrine/schema.yml |
17 | 1 | Guillermo Zdanowicz | |
18 | 1 | Guillermo Zdanowicz | 1 |
19 | 1 | Guillermo Zdanowicz | 2 |
20 | 1 | Guillermo Zdanowicz | 3 |
21 | 1 | Guillermo Zdanowicz | 4 |
22 | 1 | Guillermo Zdanowicz | 5 |
23 | 1 | Guillermo Zdanowicz | 6 |
24 | 1 | Guillermo Zdanowicz | 7 |
25 | 1 | Guillermo Zdanowicz | 8 |
26 | 1 | Guillermo Zdanowicz | 9 |
27 | 1 | Guillermo Zdanowicz | 10 |
28 | 1 | Guillermo Zdanowicz | 11 |
29 | 1 | Guillermo Zdanowicz | 12 |
30 | 1 | Guillermo Zdanowicz | 13 |
31 | 1 | Guillermo Zdanowicz | 14 |
32 | 1 | Guillermo Zdanowicz | 15 |
33 | 1 | Guillermo Zdanowicz | 16 |
34 | 1 | Guillermo Zdanowicz | Persona: |
35 | 1 | Guillermo Zdanowicz | columns: |
36 | 1 | Guillermo Zdanowicz | id: { type: integer, notnull: true, primary: true, autoincrement: true } |
37 | 1 | Guillermo Zdanowicz | nombre: { type: string(100), notnull: true } |
38 | 1 | Guillermo Zdanowicz | apellido: { type: string(100), notnull: true } |
39 | 1 | Guillermo Zdanowicz | usuario: { type: string(20), notnull: true } |
40 | 1 | Guillermo Zdanowicz | clave: { type: string(100), notnull: true } |
41 | 1 | Guillermo Zdanowicz | pais_id: { type: integer, notnull: true } |
42 | 1 | Guillermo Zdanowicz | relations: |
43 | 1 | Guillermo Zdanowicz | Pais: |
44 | 1 | Guillermo Zdanowicz | foreignAlias: Persona |
45 | 1 | Guillermo Zdanowicz | |
46 | 1 | Guillermo Zdanowicz | Pais: |
47 | 1 | Guillermo Zdanowicz | columns: |
48 | 1 | Guillermo Zdanowicz | id: { type: integer, notnull: true, primary: true, autoincrement: true } |
49 | 1 | Guillermo Zdanowicz | nombre: { type: string(100), notnull: true } |
50 | 1 | Guillermo Zdanowicz | Por lo general dentro de un modelo, por ejemplo PersonaTable.class.php, creamos métodos con los DQLs necesarios para un SELECT a la base de datos. |
51 | 1 | Guillermo Zdanowicz | |
52 | 1 | Guillermo Zdanowicz | »lib/model/PersonaTable.class.php |
53 | 1 | Guillermo Zdanowicz | |
54 | 1 | Guillermo Zdanowicz | 1 |
55 | 1 | Guillermo Zdanowicz | 2 |
56 | 1 | Guillermo Zdanowicz | 3 |
57 | 1 | Guillermo Zdanowicz | 4 |
58 | 1 | Guillermo Zdanowicz | 5 |
59 | 1 | Guillermo Zdanowicz | 6 |
60 | 1 | Guillermo Zdanowicz | 7 |
61 | 1 | Guillermo Zdanowicz | 8 |
62 | 1 | Guillermo Zdanowicz | 9 |
63 | 1 | Guillermo Zdanowicz | 10 |
64 | 1 | Guillermo Zdanowicz | 11 |
65 | 1 | Guillermo Zdanowicz | 12 |
66 | 1 | Guillermo Zdanowicz | 13 |
67 | 1 | Guillermo Zdanowicz | 14 |
68 | 1 | Guillermo Zdanowicz | 15 |
69 | 1 | Guillermo Zdanowicz | 16 |
70 | 1 | Guillermo Zdanowicz | 17 |
71 | 1 | Guillermo Zdanowicz | class PersonaTable extends Doctrine_Table |
72 | 1 | Guillermo Zdanowicz | { |
73 | 1 | Guillermo Zdanowicz | public static function getInstance() |
74 | 1 | Guillermo Zdanowicz | { |
75 | 1 | Guillermo Zdanowicz | return Doctrine_Core::getTable('Persona'); |
76 | 1 | Guillermo Zdanowicz | } |
77 | 1 | Guillermo Zdanowicz | |
78 | 1 | Guillermo Zdanowicz | public function getPersonasByUsuario($usuario) |
79 | 1 | Guillermo Zdanowicz | { |
80 | 1 | Guillermo Zdanowicz | $ret = Doctrine_Query::create() |
81 | 1 | Guillermo Zdanowicz | ->from('Persona p') |
82 | 1 | Guillermo Zdanowicz | ->where('p.usuario = ?', $usuario) |
83 | 1 | Guillermo Zdanowicz | ->execute(); |
84 | 1 | Guillermo Zdanowicz | |
85 | 1 | Guillermo Zdanowicz | return $ret; |
86 | 1 | Guillermo Zdanowicz | } |
87 | 1 | Guillermo Zdanowicz | } |
88 | 1 | Guillermo Zdanowicz | Podemos ver en las líneas 8 a la 16 un método público que genera un DQL para traer todas las columnas de la tabla persona cuando el usuario sea igual al que viene por argumento. Este DQL sería traducido al siguiente SQL: |
89 | 1 | Guillermo Zdanowicz | |
90 | 1 | Guillermo Zdanowicz | 1 |
91 | 1 | Guillermo Zdanowicz | 2 |
92 | 1 | Guillermo Zdanowicz | 3 |
93 | 1 | Guillermo Zdanowicz | 4 |
94 | 1 | Guillermo Zdanowicz | SELECT p.id AS p__id, p.nombre AS p__nombre, p.apellido AS p__apellido, |
95 | 1 | Guillermo Zdanowicz | p.usuario AS p__usuario, p.clave AS p__clave, p.pais_id AS p__pais_id |
96 | 1 | Guillermo Zdanowicz | FROM persona p |
97 | 1 | Guillermo Zdanowicz | WHERE (p.usuario = 'jperez') |
98 | 1 | Guillermo Zdanowicz | Existen cuatro tipos básicos de Data Hydrators: |
99 | 1 | Guillermo Zdanowicz | |
100 | 1 | Guillermo Zdanowicz | Record: Devuelve los datos como un array de objetos |
101 | 1 | Guillermo Zdanowicz | Array: Devuelve los datos como un array de arrays multidimensionales donde cada Foreing Key que este contenida dentro de nuestro query será nuevamente un array |
102 | 1 | Guillermo Zdanowicz | Scalar: Devuelve los datos como un array plano. Este sería el más conocido a nivel de conexiones básicas con PHP por ejemplo usando mysql_query y mysql_fetch_array |
103 | 1 | Guillermo Zdanowicz | Single Scalar: Este Data Hydrator nos sirve para obtener solo un dato por ejemplo si hacemos un select nombre from persona where id = 1 o un simple select now() |
104 | 1 | Guillermo Zdanowicz | Empecemos a verlos uno por uno. |
105 | 1 | Guillermo Zdanowicz | |
106 | 1 | Guillermo Zdanowicz | Data Hydrator: Record |
107 | 1 | Guillermo Zdanowicz | |
108 | 1 | Guillermo Zdanowicz | Con el ejemplo visto más arriba se puede notar que hicimos un simple DQL y no nos importó el Data Hydrator. Esto es porque por default el Data Hydrator asignado será el Record. Esto también lo podemos escribir explícitamente escribiendo: |
109 | 1 | Guillermo Zdanowicz | |
110 | 1 | Guillermo Zdanowicz | »lib/model/PersonaTable.class.php |
111 | 1 | Guillermo Zdanowicz | |
112 | 1 | Guillermo Zdanowicz | 1 |
113 | 1 | Guillermo Zdanowicz | 2 |
114 | 1 | Guillermo Zdanowicz | 3 |
115 | 1 | Guillermo Zdanowicz | 4 |
116 | 1 | Guillermo Zdanowicz | 5 |
117 | 1 | Guillermo Zdanowicz | 6 |
118 | 1 | Guillermo Zdanowicz | 7 |
119 | 1 | Guillermo Zdanowicz | 8 |
120 | 1 | Guillermo Zdanowicz | 9 |
121 | 1 | Guillermo Zdanowicz | 10 |
122 | 1 | Guillermo Zdanowicz | public function getPersonasByUsuario($usuario) |
123 | 1 | Guillermo Zdanowicz | { |
124 | 1 | Guillermo Zdanowicz | $ret = Doctrine_Query::create() |
125 | 1 | Guillermo Zdanowicz | ->from('Persona p') |
126 | 1 | Guillermo Zdanowicz | ->where('p.usuario = ?', $usuario) |
127 | 1 | Guillermo Zdanowicz | ->setHydrationMode(Doctrine::HYDRATE_RECORD) |
128 | 1 | Guillermo Zdanowicz | ->execute(); |
129 | 1 | Guillermo Zdanowicz | |
130 | 1 | Guillermo Zdanowicz | return $ret; |
131 | 1 | Guillermo Zdanowicz | } |
132 | 1 | Guillermo Zdanowicz | Como podemos ver en la línea 6, tenemos un método del Doctrine_Query llamado ->setHydrationMode() que nos permite enviar valores por cada uno. Para hacerlo más sencillo Doctrine ya nos prepara una constantes de la cuales la primera es Doctrine::HYDRATE_RECORD para asignar el tipo de hidratación Record. |
133 | 1 | Guillermo Zdanowicz | |
134 | 1 | Guillermo Zdanowicz | Agregando entonces este método como lo vemos en el ejemplo, o dejándolo sin nada, doctrine nos devuelve los datos como un array de objetos que podríamos invocarlo en un action de esta manera para luego iterarlo: |
135 | 1 | Guillermo Zdanowicz | |
136 | 1 | Guillermo Zdanowicz | »apps/frontend/modules/tests/actions/actions.class.php |
137 | 1 | Guillermo Zdanowicz | |
138 | 1 | Guillermo Zdanowicz | 1 |
139 | 1 | Guillermo Zdanowicz | 2 |
140 | 1 | Guillermo Zdanowicz | 3 |
141 | 1 | Guillermo Zdanowicz | 4 |
142 | 1 | Guillermo Zdanowicz | 5 |
143 | 1 | Guillermo Zdanowicz | 6 |
144 | 1 | Guillermo Zdanowicz | 7 |
145 | 1 | Guillermo Zdanowicz | 8 |
146 | 1 | Guillermo Zdanowicz | 9 |
147 | 1 | Guillermo Zdanowicz | public function executeIndex(sfWebRequest $request) |
148 | 1 | Guillermo Zdanowicz | { |
149 | 1 | Guillermo Zdanowicz | $personas = PersonaTable::getInstance()->getPersonasByUsuario('jperez'); |
150 | 1 | Guillermo Zdanowicz | |
151 | 1 | Guillermo Zdanowicz | foreach($personas as $persona) |
152 | 1 | Guillermo Zdanowicz | { |
153 | 1 | Guillermo Zdanowicz | $this->logMessage($persona->getNombre()); |
154 | 1 | Guillermo Zdanowicz | } |
155 | 1 | Guillermo Zdanowicz | } |
156 | 1 | Guillermo Zdanowicz | Fijense como obtenemos los datos como si fuera un objeto utilizando los getters: getId(), getNombre(), getUsuario(), getPaisId(), etc. |
157 | 1 | Guillermo Zdanowicz | |
158 | 1 | Guillermo Zdanowicz | El punto fuerte de este Data Hydrator es que si se fijan tenemos una columna pais_id por lo que si queremos obtener el nombre del país podríamos hacer uso de los getters para que Doctrine haga una consulta nueva y obtenga los datos del país de la siguiente manera: |
159 | 1 | Guillermo Zdanowicz | |
160 | 1 | Guillermo Zdanowicz | 1 |
161 | 1 | Guillermo Zdanowicz | 2 |
162 | 1 | Guillermo Zdanowicz | 3 |
163 | 1 | Guillermo Zdanowicz | //-- Fijense que uso el getter getPais() y no getPaisId() |
164 | 1 | Guillermo Zdanowicz | // ya que tiene que obtener el país completo |
165 | 1 | Guillermo Zdanowicz | $pais = $persona->getPais()->getNombre(); |
166 | 1 | Guillermo Zdanowicz | Doctrine se da cuenta que queremos acceder a un dato de la FK por lo que cuando ejecutamos getPais() vuelve a enviar un select * from pais where id = X y obtiene los datos del país correspondiente a la persona. |
167 | 1 | Guillermo Zdanowicz | |
168 | 1 | Guillermo Zdanowicz | Hay que notar que aunque esta funcionalidad es muy interesante se ejecutan 2 consultas a la base de datos. Una para obtener los datos de la persona y otra para los datos del país. Lo cual sería mucho más útil resolverlo con un JOIN modificando nuestro DQL y de esta manera cuando ejecutemos getPais()->getNombre() Doctrine ya tendrá el dato cargado y no tendrá la necesidad de ejecutar una segundo consulta. |
169 | 1 | Guillermo Zdanowicz | |
170 | 1 | Guillermo Zdanowicz | El DQL que podríamos usar para hacer el JOIN sería el siguiente: |
171 | 1 | Guillermo Zdanowicz | |
172 | 1 | Guillermo Zdanowicz | »lib/model/PersonaTable.class.php |
173 | 1 | Guillermo Zdanowicz | |
174 | 1 | Guillermo Zdanowicz | 1 |
175 | 1 | Guillermo Zdanowicz | 2 |
176 | 1 | Guillermo Zdanowicz | 3 |
177 | 1 | Guillermo Zdanowicz | 4 |
178 | 1 | Guillermo Zdanowicz | 5 |
179 | 1 | Guillermo Zdanowicz | 6 |
180 | 1 | Guillermo Zdanowicz | 7 |
181 | 1 | Guillermo Zdanowicz | 8 |
182 | 1 | Guillermo Zdanowicz | 9 |
183 | 1 | Guillermo Zdanowicz | 10 |
184 | 1 | Guillermo Zdanowicz | 11 |
185 | 1 | Guillermo Zdanowicz | public function getPersonasByUsuario($usuario) |
186 | 1 | Guillermo Zdanowicz | { |
187 | 1 | Guillermo Zdanowicz | $ret = Doctrine_Query::create() |
188 | 1 | Guillermo Zdanowicz | ->from('Persona p') |
189 | 1 | Guillermo Zdanowicz | ->where('p.usuario = ?', $usuario) |
190 | 1 | Guillermo Zdanowicz | ->innerJoin('p.Pais pa') |
191 | 1 | Guillermo Zdanowicz | ->setHydrationMode(Doctrine::HYDRATE_RECORD) |
192 | 1 | Guillermo Zdanowicz | ->execute(); |
193 | 1 | Guillermo Zdanowicz | |
194 | 1 | Guillermo Zdanowicz | return $ret; |
195 | 1 | Guillermo Zdanowicz | } |
196 | 1 | Guillermo Zdanowicz | Data Hydrator: Array |
197 | 1 | Guillermo Zdanowicz | |
198 | 1 | Guillermo Zdanowicz | Este Data Hydrator me resultó un poco raro hasta que lo entendí bien y es importante entenderlo para no mezclarlo con la idea que siempre tenemos de obtener los registros de la base de datos como arrays planos. |
199 | 1 | Guillermo Zdanowicz | |
200 | 1 | Guillermo Zdanowicz | Para obtener este Data Hydrator modificamos el método correspondiente en nuestro DQL: |
201 | 1 | Guillermo Zdanowicz | |
202 | 1 | Guillermo Zdanowicz | »lib/model/PersonaTable.class.php |
203 | 1 | Guillermo Zdanowicz | |
204 | 1 | Guillermo Zdanowicz | 1 |
205 | 1 | Guillermo Zdanowicz | 2 |
206 | 1 | Guillermo Zdanowicz | 3 |
207 | 1 | Guillermo Zdanowicz | 4 |
208 | 1 | Guillermo Zdanowicz | 5 |
209 | 1 | Guillermo Zdanowicz | 6 |
210 | 1 | Guillermo Zdanowicz | 7 |
211 | 1 | Guillermo Zdanowicz | 8 |
212 | 1 | Guillermo Zdanowicz | 9 |
213 | 1 | Guillermo Zdanowicz | 10 |
214 | 1 | Guillermo Zdanowicz | public function getPersonasByUsuario($usuario) |
215 | 1 | Guillermo Zdanowicz | { |
216 | 1 | Guillermo Zdanowicz | $ret = Doctrine_Query::create() |
217 | 1 | Guillermo Zdanowicz | ->from('Persona p') |
218 | 1 | Guillermo Zdanowicz | ->where('p.usuario = ?', $usuario) |
219 | 1 | Guillermo Zdanowicz | ->setHydrationMode(Doctrine::HYDRATE_ARRAY) |
220 | 1 | Guillermo Zdanowicz | ->execute(); |
221 | 1 | Guillermo Zdanowicz | |
222 | 1 | Guillermo Zdanowicz | return $ret; |
223 | 1 | Guillermo Zdanowicz | } |
224 | 1 | Guillermo Zdanowicz | También podríamos obtenerlo usando el método ->fetchArray() en lugar de ->execute(). |
225 | 1 | Guillermo Zdanowicz | |
226 | 1 | Guillermo Zdanowicz | »lib/model/PersonaTable.class.php |
227 | 1 | Guillermo Zdanowicz | |
228 | 1 | Guillermo Zdanowicz | 1 |
229 | 1 | Guillermo Zdanowicz | 2 |
230 | 1 | Guillermo Zdanowicz | 3 |
231 | 1 | Guillermo Zdanowicz | 4 |
232 | 1 | Guillermo Zdanowicz | 5 |
233 | 1 | Guillermo Zdanowicz | 6 |
234 | 1 | Guillermo Zdanowicz | 7 |
235 | 1 | Guillermo Zdanowicz | 8 |
236 | 1 | Guillermo Zdanowicz | 9 |
237 | 1 | Guillermo Zdanowicz | public function getPersonasByUsuario($usuario) |
238 | 1 | Guillermo Zdanowicz | { |
239 | 1 | Guillermo Zdanowicz | $ret = Doctrine_Query::create() |
240 | 1 | Guillermo Zdanowicz | ->from('Persona p') |
241 | 1 | Guillermo Zdanowicz | ->where('p.usuario = ?', $usuario) |
242 | 1 | Guillermo Zdanowicz | ->fetchArray(); |
243 | 1 | Guillermo Zdanowicz | |
244 | 1 | Guillermo Zdanowicz | return $ret; |
245 | 1 | Guillermo Zdanowicz | } |
246 | 1 | Guillermo Zdanowicz | Con esto obtenemos un array un poco complicado que intenta simular un array de objetos con un array de arrays asociativos. Para ejemplificar un poco más muestro la estructura del array que obtenemos con la consulta. |
247 | 1 | Guillermo Zdanowicz | |
248 | 1 | Guillermo Zdanowicz | 1 |
249 | 1 | Guillermo Zdanowicz | 2 |
250 | 1 | Guillermo Zdanowicz | 3 |
251 | 1 | Guillermo Zdanowicz | 4 |
252 | 1 | Guillermo Zdanowicz | 5 |
253 | 1 | Guillermo Zdanowicz | 6 |
254 | 1 | Guillermo Zdanowicz | 7 |
255 | 1 | Guillermo Zdanowicz | 8 |
256 | 1 | Guillermo Zdanowicz | 9 |
257 | 1 | Guillermo Zdanowicz | 10 |
258 | 1 | Guillermo Zdanowicz | 11 |
259 | 1 | Guillermo Zdanowicz | Array |
260 | 1 | Guillermo Zdanowicz | ( |
261 | 1 | Guillermo Zdanowicz | 0 => array( |
262 | 1 | Guillermo Zdanowicz | 'id' => '1', |
263 | 1 | Guillermo Zdanowicz | 'nombre' => 'Juan', |
264 | 1 | Guillermo Zdanowicz | 'apellido' => 'Perez', |
265 | 1 | Guillermo Zdanowicz | 'usuario' => 'jperez', |
266 | 1 | Guillermo Zdanowicz | 'clave' => '123456', |
267 | 1 | Guillermo Zdanowicz | 'pais_id' => '1', |
268 | 1 | Guillermo Zdanowicz | ) |
269 | 1 | Guillermo Zdanowicz | ) |
270 | 1 | Guillermo Zdanowicz | En este caso como obtenemos un solo usuario entonces solo tenemos la posición cero que contiene un array con los datos necesarios. Hasta aquí es normal y sin son varios simplemente hacemos un bucle sobre el array principal y obtenemos los datos: |
271 | 1 | Guillermo Zdanowicz | |
272 | 1 | Guillermo Zdanowicz | 1 |
273 | 1 | Guillermo Zdanowicz | 2 |
274 | 1 | Guillermo Zdanowicz | 3 |
275 | 1 | Guillermo Zdanowicz | 4 |
276 | 1 | Guillermo Zdanowicz | 5 |
277 | 1 | Guillermo Zdanowicz | 6 |
278 | 1 | Guillermo Zdanowicz | foreach($personas as $persona) |
279 | 1 | Guillermo Zdanowicz | { |
280 | 1 | Guillermo Zdanowicz | echo $persona['nombre']; |
281 | 1 | Guillermo Zdanowicz | echo $persona['usuario']; |
282 | 1 | Guillermo Zdanowicz | echo $persona['pais_id']; |
283 | 1 | Guillermo Zdanowicz | } |
284 | 1 | Guillermo Zdanowicz | El problema que yo encuentro es cuando dentro del DQL empezamos a utilizar JOINs por ejemplo para obtener el nombre del Pais obtendríamos una posición Pais que hace referencia a la tabla foránea y dentro nuevamente un array con los datos del país: |
285 | 1 | Guillermo Zdanowicz | |
286 | 1 | Guillermo Zdanowicz | 1 |
287 | 1 | Guillermo Zdanowicz | 2 |
288 | 1 | Guillermo Zdanowicz | 3 |
289 | 1 | Guillermo Zdanowicz | 4 |
290 | 1 | Guillermo Zdanowicz | 5 |
291 | 1 | Guillermo Zdanowicz | 6 |
292 | 1 | Guillermo Zdanowicz | 7 |
293 | 1 | Guillermo Zdanowicz | 8 |
294 | 1 | Guillermo Zdanowicz | 9 |
295 | 1 | Guillermo Zdanowicz | 10 |
296 | 1 | Guillermo Zdanowicz | 11 |
297 | 1 | Guillermo Zdanowicz | 12 |
298 | 1 | Guillermo Zdanowicz | 13 |
299 | 1 | Guillermo Zdanowicz | 14 |
300 | 1 | Guillermo Zdanowicz | 15 |
301 | 1 | Guillermo Zdanowicz | Array |
302 | 1 | Guillermo Zdanowicz | ( |
303 | 1 | Guillermo Zdanowicz | 0 => array( |
304 | 1 | Guillermo Zdanowicz | 'id' => '1', |
305 | 1 | Guillermo Zdanowicz | 'nombre' => 'Juan', |
306 | 1 | Guillermo Zdanowicz | 'apellido' => 'Perez', |
307 | 1 | Guillermo Zdanowicz | 'usuario' => 'jperez', |
308 | 1 | Guillermo Zdanowicz | 'clave' => '123456', |
309 | 1 | Guillermo Zdanowicz | 'pais_id' => '1', |
310 | 1 | Guillermo Zdanowicz | 'Pais' => array( |
311 | 1 | Guillermo Zdanowicz | 'id' => '1', |
312 | 1 | Guillermo Zdanowicz | 'nombre' => 'Brasil' |
313 | 1 | Guillermo Zdanowicz | ), |
314 | 1 | Guillermo Zdanowicz | ) |
315 | 1 | Guillermo Zdanowicz | ) |
316 | 1 | Guillermo Zdanowicz | Al querer obtener los datos sería algo así: |
317 | 1 | Guillermo Zdanowicz | |
318 | 1 | Guillermo Zdanowicz | 1 |
319 | 1 | Guillermo Zdanowicz | 2 |
320 | 1 | Guillermo Zdanowicz | 3 |
321 | 1 | Guillermo Zdanowicz | 4 |
322 | 1 | Guillermo Zdanowicz | 5 |
323 | 1 | Guillermo Zdanowicz | 6 |
324 | 1 | Guillermo Zdanowicz | foreach($personas as $persona) |
325 | 1 | Guillermo Zdanowicz | { |
326 | 1 | Guillermo Zdanowicz | echo $persona['nombre']; |
327 | 1 | Guillermo Zdanowicz | echo $persona['usuario']; |
328 | 1 | Guillermo Zdanowicz | echo $persona['Pais']['nombre']; |
329 | 1 | Guillermo Zdanowicz | } |
330 | 1 | Guillermo Zdanowicz | Como lo ven es una forma de simular la orientación de objetos con Arrays. Lo único que tienen que saber es que si la tabla País tiene una FK a Ciudades por ejemplo tendríamos nuevamente otro Array y para obtener el nombre de la ciudad seria $persona['Pais']['Ciudad']['nombre']. |
331 | 1 | Guillermo Zdanowicz | |
332 | 1 | Guillermo Zdanowicz | La desventaja aquí es que si no traje el nombre del País en el select de mi DQL, utilizando el innerJoin, ya no podré hacer uso de ->getPais()->getNombre() y Doctrine no hará un select por separado para tratar de obtener el dato, esto solo ocurre con el Data Hydrator: Record pero el array devuelto por doctrine es mucho menor que cuando usamos el tipo Record justamente por no tener estas posibilidades. |
333 | 1 | Guillermo Zdanowicz | |
334 | 1 | Guillermo Zdanowicz | Data Hydrator: Scalar |
335 | 1 | Guillermo Zdanowicz | |
336 | 1 | Guillermo Zdanowicz | El tipo Scalar es muy parecido al tipo Array con la diferencia que no simula la orientación a objetos sino que simplemente nos devuelve un array plano utilizando para el nombre de los índices el nombre de la columna con el prefijo del alias utilizado para la tabla, por lo que para el siguiente DQL tendríamos el siguiente Array: |
337 | 1 | Guillermo Zdanowicz | |
338 | 1 | Guillermo Zdanowicz | »lib/model/PersonaTable.class.php |
339 | 1 | Guillermo Zdanowicz | |
340 | 1 | Guillermo Zdanowicz | 1 |
341 | 1 | Guillermo Zdanowicz | 2 |
342 | 1 | Guillermo Zdanowicz | 3 |
343 | 1 | Guillermo Zdanowicz | 4 |
344 | 1 | Guillermo Zdanowicz | 5 |
345 | 1 | Guillermo Zdanowicz | 6 |
346 | 1 | Guillermo Zdanowicz | 7 |
347 | 1 | Guillermo Zdanowicz | 8 |
348 | 1 | Guillermo Zdanowicz | 9 |
349 | 1 | Guillermo Zdanowicz | 10 |
350 | 1 | Guillermo Zdanowicz | public function getPersonasByUsuario($usuario) |
351 | 1 | Guillermo Zdanowicz | { |
352 | 1 | Guillermo Zdanowicz | $ret = Doctrine_Query::create() |
353 | 1 | Guillermo Zdanowicz | ->from('Persona p') |
354 | 1 | Guillermo Zdanowicz | ->where('p.usuario = ?', $usuario) |
355 | 1 | Guillermo Zdanowicz | ->setHydrationMode(Doctrine::HYDRATE_SCALAR) |
356 | 1 | Guillermo Zdanowicz | ->execute(); |
357 | 1 | Guillermo Zdanowicz | |
358 | 1 | Guillermo Zdanowicz | return $ret; |
359 | 1 | Guillermo Zdanowicz | } |
360 | 1 | Guillermo Zdanowicz | 1 |
361 | 1 | Guillermo Zdanowicz | 2 |
362 | 1 | Guillermo Zdanowicz | 3 |
363 | 1 | Guillermo Zdanowicz | 4 |
364 | 1 | Guillermo Zdanowicz | 5 |
365 | 1 | Guillermo Zdanowicz | 6 |
366 | 1 | Guillermo Zdanowicz | 7 |
367 | 1 | Guillermo Zdanowicz | 8 |
368 | 1 | Guillermo Zdanowicz | 9 |
369 | 1 | Guillermo Zdanowicz | 10 |
370 | 1 | Guillermo Zdanowicz | 11 |
371 | 1 | Guillermo Zdanowicz | Array |
372 | 1 | Guillermo Zdanowicz | ( |
373 | 1 | Guillermo Zdanowicz | 0 => array( |
374 | 1 | Guillermo Zdanowicz | 'p_id' => '1', |
375 | 1 | Guillermo Zdanowicz | 'p_nombre' => 'Juan', |
376 | 1 | Guillermo Zdanowicz | 'p_apellido' => 'Perez', |
377 | 1 | Guillermo Zdanowicz | 'p_usuario' => 'jperez', |
378 | 1 | Guillermo Zdanowicz | 'p_clave' => '123456', |
379 | 1 | Guillermo Zdanowicz | 'p_pais_id' => '1', |
380 | 1 | Guillermo Zdanowicz | ) |
381 | 1 | Guillermo Zdanowicz | ) |
382 | 1 | Guillermo Zdanowicz | Hasta aquí la única diferencia es que se le agrega “p_” al nombre de las columnas porque elegí el alias “p” al hacer ->from(‘Persona p’). La gran diferencia se nota al utilizar los JOINs donde, utilizando el código con el JOIN que utiliza el alias “pa” para el país obtendríamos un Array plano también como el anterior: |
383 | 1 | Guillermo Zdanowicz | |
384 | 1 | Guillermo Zdanowicz | 1 |
385 | 1 | Guillermo Zdanowicz | 2 |
386 | 1 | Guillermo Zdanowicz | 3 |
387 | 1 | Guillermo Zdanowicz | 4 |
388 | 1 | Guillermo Zdanowicz | 5 |
389 | 1 | Guillermo Zdanowicz | 6 |
390 | 1 | Guillermo Zdanowicz | 7 |
391 | 1 | Guillermo Zdanowicz | 8 |
392 | 1 | Guillermo Zdanowicz | 9 |
393 | 1 | Guillermo Zdanowicz | 10 |
394 | 1 | Guillermo Zdanowicz | 11 |
395 | 1 | Guillermo Zdanowicz | 12 |
396 | 1 | Guillermo Zdanowicz | 13 |
397 | 1 | Guillermo Zdanowicz | Array |
398 | 1 | Guillermo Zdanowicz | ( |
399 | 1 | Guillermo Zdanowicz | 0 => array( |
400 | 1 | Guillermo Zdanowicz | 'p_id' => '1', |
401 | 1 | Guillermo Zdanowicz | 'p_nombre' => 'Juan', |
402 | 1 | Guillermo Zdanowicz | 'p_apellido' => 'Perez', |
403 | 1 | Guillermo Zdanowicz | 'p_usuario' => 'jperez', |
404 | 1 | Guillermo Zdanowicz | 'p_clave' => '123456', |
405 | 1 | Guillermo Zdanowicz | 'p_pais_id' => 1, |
406 | 1 | Guillermo Zdanowicz | 'pa_id' => '1', |
407 | 1 | Guillermo Zdanowicz | 'pa_nombre' => 'Brasil', |
408 | 1 | Guillermo Zdanowicz | ) |
409 | 1 | Guillermo Zdanowicz | ) |
410 | 1 | Guillermo Zdanowicz | Este tipo de Arrays suele ser util para funciones genéricas como por ejemplo un helper que imprima una tabla a partir de un array. |
411 | 1 | Guillermo Zdanowicz | |
412 | 1 | Guillermo Zdanowicz | Data Hydrator: Single Scalar |
413 | 1 | Guillermo Zdanowicz | |
414 | 1 | Guillermo Zdanowicz | Este tipo de Data Hydrator es muy sencillo. Simplemente se utiliza cuando lo que yo quiero obtener de la base de datos es “un solo dato y nada más que eso“. En este caso no obtendríamos un array ni de objetos ni de arrays sino “un solo dato“. |
415 | 1 | Guillermo Zdanowicz | |
416 | 1 | Guillermo Zdanowicz | Podríamos usarlo para el siguiente DQL con la idea de obtener el nombre de usuario de un determinado ID: |
417 | 1 | Guillermo Zdanowicz | |
418 | 1 | Guillermo Zdanowicz | 1 |
419 | 1 | Guillermo Zdanowicz | 2 |
420 | 1 | Guillermo Zdanowicz | 3 |
421 | 1 | Guillermo Zdanowicz | 4 |
422 | 1 | Guillermo Zdanowicz | 5 |
423 | 1 | Guillermo Zdanowicz | 6 |
424 | 1 | Guillermo Zdanowicz | 7 |
425 | 1 | Guillermo Zdanowicz | 8 |
426 | 1 | Guillermo Zdanowicz | 9 |
427 | 1 | Guillermo Zdanowicz | 10 |
428 | 1 | Guillermo Zdanowicz | 11 |
429 | 1 | Guillermo Zdanowicz | public function getUsuarioById($id) |
430 | 1 | Guillermo Zdanowicz | { |
431 | 1 | Guillermo Zdanowicz | $usuario = Doctrine_Query::create() |
432 | 1 | Guillermo Zdanowicz | ->select('p.usuario') |
433 | 1 | Guillermo Zdanowicz | ->from('Persona p') |
434 | 1 | Guillermo Zdanowicz | ->where('p.id = ?', $id) |
435 | 1 | Guillermo Zdanowicz | ->setHydrationMode(Doctrine::HYDRATE_SINGLE_SCALAR) |
436 | 1 | Guillermo Zdanowicz | ->execute(); |
437 | 1 | Guillermo Zdanowicz | |
438 | 1 | Guillermo Zdanowicz | return $usuario; |
439 | 1 | Guillermo Zdanowicz | } |
440 | 1 | Guillermo Zdanowicz | De esta forma lo que se obtiene es simplemente el nombre del usuario y podríamos utilizarlo en el action de la siguiente manera: |
441 | 1 | Guillermo Zdanowicz | |
442 | 1 | Guillermo Zdanowicz | »apps/frontend/modules/tests/actions/actions.class.php |
443 | 1 | Guillermo Zdanowicz | |
444 | 1 | Guillermo Zdanowicz | 1 |
445 | 1 | Guillermo Zdanowicz | 2 |
446 | 1 | Guillermo Zdanowicz | 3 |
447 | 1 | Guillermo Zdanowicz | 4 |
448 | 1 | Guillermo Zdanowicz | 5 |
449 | 1 | Guillermo Zdanowicz | 6 |
450 | 1 | Guillermo Zdanowicz | public function executeIndex(sfWebRequest $request) |
451 | 1 | Guillermo Zdanowicz | { |
452 | 1 | Guillermo Zdanowicz | $usuario = PersonaTable::getInstance()->getUsuarioById(1); |
453 | 1 | Guillermo Zdanowicz | |
454 | 1 | Guillermo Zdanowicz | $this->logMessage($usuario); |
455 | 1 | Guillermo Zdanowicz | } |
456 | 1 | Guillermo Zdanowicz | Resumen Final |
457 | 1 | Guillermo Zdanowicz | |
458 | 1 | Guillermo Zdanowicz | Haciendo un resumen final podríamos decir que: |
459 | 1 | Guillermo Zdanowicz | |
460 | 1 | Guillermo Zdanowicz | Record: Array de objetos |
461 | 1 | Guillermo Zdanowicz | Array: Array de Arrays multidimensionales. Simulan orientación a objetos con Arrays asociativos |
462 | 1 | Guillermo Zdanowicz | Scalar: Array de Arrays planos |
463 | 1 | Guillermo Zdanowicz | Single Scalar: Un solo dato |
464 | 1 | Guillermo Zdanowicz | También podríamos decir que la funcionalidad de obtener datos que no fueron seleccionados en nuestro DQL al no haber hecho los JOINs solo lo tiene el tipo Record a través de los getters ya que si Doctrine lo detecta como un datos nulo hará automáticamente un select nuevamente a la base de datos. Los tipos Array, Scalar y Single Scalar no poseen esta funcionalidad por no tratarse de objetos. |
465 | 1 | Guillermo Zdanowicz | |
466 | 1 | Guillermo Zdanowicz | También es bueno saber que el Record justamente por contar con la funcionalidad mencionada arriba ocupan más lugar en memoria por lo que yo suelo pensar que la mejor manera es preveer bien los campos que quiero seleccionar y manejarlo como un Array. |
467 | 1 | Guillermo Zdanowicz | |
468 | 1 | Guillermo Zdanowicz | Espero que les haya servido. Hasta la próxima. |
469 | 1 | Guillermo Zdanowicz | |
470 | 1 | Guillermo Zdanowicz | Data Hydrators con Symfony 1.4 y Doctrine, 5.0 out of 5 based on 2 ratings |