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
Redmine Appliance - Powered by TurnKey Linux