-
Notifications
You must be signed in to change notification settings - Fork 24
/
toba_datos_relacion.php
785 lines (714 loc) · 24.2 KB
/
toba_datos_relacion.php
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
383
384
385
386
387
388
389
390
391
392
393
394
395
396
397
398
399
400
401
402
403
404
405
406
407
408
409
410
411
412
413
414
415
416
417
418
419
420
421
422
423
424
425
426
427
428
429
430
431
432
433
434
435
436
437
438
439
440
441
442
443
444
445
446
447
448
449
450
451
452
453
454
455
456
457
458
459
460
461
462
463
464
465
466
467
468
469
470
471
472
473
474
475
476
477
478
479
480
481
482
483
484
485
486
487
488
489
490
491
492
493
494
495
496
497
498
499
500
501
502
503
504
505
506
507
508
509
510
511
512
513
514
515
516
517
518
519
520
521
522
523
524
525
526
527
528
529
530
531
532
533
534
535
536
537
538
539
540
541
542
543
544
545
546
547
548
549
550
551
552
553
554
555
556
557
558
559
560
561
562
563
564
565
566
567
568
569
570
571
572
573
574
575
576
577
578
579
580
581
582
583
584
585
586
587
588
589
590
591
592
593
594
595
596
597
598
599
600
601
602
603
604
605
606
607
608
609
610
611
612
613
614
615
616
617
618
619
620
621
622
623
624
625
626
627
628
629
630
631
632
633
634
635
636
637
638
639
640
641
642
643
644
645
646
647
648
649
650
651
652
653
654
655
656
657
658
659
660
661
662
663
664
665
666
667
668
669
670
671
672
673
674
675
676
677
678
679
680
681
682
683
684
685
686
687
688
689
690
691
692
693
694
695
696
697
698
699
700
701
702
703
704
705
706
707
708
709
710
711
712
713
714
715
716
717
718
719
720
721
722
723
724
725
726
727
728
729
730
731
732
733
734
735
736
737
738
739
740
741
742
743
744
745
746
747
748
749
750
751
752
753
754
755
756
757
758
759
760
761
762
763
764
765
766
767
768
769
770
771
772
773
774
775
776
777
778
779
780
781
782
783
784
785
<?php
/**
* Mantiene un conjunto relacionado de @see toba_datos_tabla , brindando servicios para cargar y sincronizar esta relación con algún medio de persistencia (general una BD relacional)
*
* TODO En el dump_esquema incluir la posición actual de los cursores
* @package Componentes\Persistencia
*/
class toba_datos_relacion extends toba_componente
{
protected $_info_estructura;
protected $_relaciones = array();
protected $_tablas_raiz;
protected $_persistidor;
protected $_cargado = false;
protected $_relaciones_mapeos=array(); //Mapeo entre filas de las tablas
protected $_relaciones_mapeos_eliminados=array();//Mapeo entre filas eliminadas en el hijo
static protected $debug_pasadas; //Mantiene la cantidad de pasadas para generar ids unicos en js
protected $_info_columnas_asoc_rel;
protected $_tablas_inactivas = array();
/**
* @ignore
*/
final function __construct($id)
{
$propiedades[] = "_relaciones_mapeos_eliminados";
$propiedades[] = "_relaciones_mapeos";
$propiedades[] = "_cargado";
$this->set_propiedades_sesion($propiedades);
parent::__construct($id);
$this->crear_tablas();
}
/**
* Método interno para iniciar el componente una vez construido
* @ignore
*/
function inicializar($parametros=array())
{
parent::inicializar($parametros);
$this->crear_relaciones();
if ($this->_info_estructura['debug']) {
$this->dump_esquema("INICIO: ".$this->_info['nombre']);
}
foreach ($this->_dependencias as $dep) {
$dep->inicializar($parametros);
}
}
/**
* Ventana para agregar configuraciones particulares al inicio de la vida completa del componente
* @ventana
*/
function ini(){}
/**
* @ignore
*/
function destruir()
{
//Esta clase es la encargada de guardarle los valores en sesion a cada relación
//Se asume que las relaciones siempre se cargan en el mismo orden
$this->_relaciones_mapeos = array();
$this->_relaciones_mapeos_eliminados = array();
foreach ($this->_relaciones as $relacion) {
$this->_relaciones_mapeos[] = $relacion->get_mapeo_filas();
$this->_relaciones_mapeos_eliminados[] = $relacion->get_mapeo_filas_eliminadas();
}
if ($this->_info_estructura['debug']) {
$this->dump_esquema("FIN: ".$this->_info['nombre']);
}
parent::destruir();
}
/**
* Carga los datos_tabla y les pone los topes mínimos y máximos
*/
private function crear_tablas()
{
foreach( $this->_lista_dependencias as $dep){
$this->cargar_dependencia($dep);
//La cantidad minima y maxima se pasan a traves de dos parametros genericos del objeto
$posicion = $this->_indice_dependencias[$dep];
$cant_min = $this->_info_dependencias[$posicion]['parametros_a'];
$cant_max = $this->_info_dependencias[$posicion]['parametros_b'];
$this->_dependencias[$dep]->set_tope_min_filas($cant_min);
$this->_dependencias[$dep]->set_tope_max_filas($cant_max);
$this->_dependencias[$dep]->set_controlador($this, $dep);
}
}
/**
* Para cada relación definida crea una toba_relacion_entre_tablas
* Determina cual es la tabla raiz
*/
private function crear_relaciones()
{
if(count($this->_info_relaciones)>0){
for($a=0;$a<count($this->_info_relaciones);$a++)
{
$id_padre = $this->_info_relaciones[$a]['padre_id'];
$id_hijo = $this->_info_relaciones[$a]['hijo_id'];
$id_relacion = $id_padre.'-'.$id_hijo;
$columnas_padre = $this->get_columnas_tabla_padre($this->_info_relaciones[$a]);
$columnas_hijas = $this->get_columnas_tabla_hija($this->_info_relaciones[$a]);
$this->_relaciones[$id_relacion] = new toba_relacion_entre_tablas( $this->_dependencias[ $id_padre ],
$columnas_padre,
$id_padre,
$this->_dependencias[ $id_hijo ],
$columnas_hijas,
$id_hijo
);
$padres[] = $this->_info_relaciones[$a]['padre_id'];
$hijos[] = $this->_info_relaciones[$a]['hijo_id'];
//Se recuperan los mapeos anteriores, si es que hay
if (isset($this->_relaciones_mapeos[$a])) {
$this->_relaciones[$id_relacion]->set_mapeo_filas($this->_relaciones_mapeos[$a]);
}
if (isset($this->_relaciones_mapeos_eliminados[$a])) {
$this->_relaciones[$id_relacion]->set_mapeo_filas_eliminadas($this->_relaciones_mapeos_eliminados[$a]);
}
}
//Padres sin hijos
$this->_tablas_raiz = array_diff( array_unique($padres), array_unique($hijos) );
}else{
//No hay relaciones
$this->_relaciones = array();
$this->_tablas_raiz = array_keys($this->_dependencias);
}
}
/**
* Deshabilita la tabla o las tablas recibidas para la carga y la sincronización
*/
function desactivar_tablas($tablas)
{
if (is_array($tablas)) {
$this->_tablas_inactivas = $tablas;
} else {
$this->_tablas_inactivas = array($tablas);
}
}
//-------------------------------------------------------------------------------
//-- DEBUG ---------------------------------------------------------------------
//-------------------------------------------------------------------------------
/**
* Muestra un dump de los datos y los cambios realizados a los mismos desde la carga
*/
function dump_contenido($etiqueta=null)
{
$etiqueta = isset($etiqueta) ? $etiqueta : 'DATOS_RELACION: ' . $this->_info['nombre'];
foreach($this->_dependencias as $id => $dependencia){
$info[$id]['cambios'] = $dependencia->get_cambios();
$info[$id]['datos'] = $dependencia->get_conjunto_datos_interno();
}
ei_arbol( $info, $etiqueta, null, true);
}
/**
* Muestra un esquema de las tablas y los mapeos de las filas
* SOLO USAR PARA DEBUG! envia todos los datos al cliente en forma plana!
*/
function dump_esquema($titulo=null)
{
//Se mantiene la cantidad de pasadas en este pedido de pagina para generar variables js unicas
if (isset(self::$debug_pasadas)) {
self::$debug_pasadas++;
} else {
self::$debug_pasadas = 1;
}
$grafo = self::grafo_relaciones($this->_info_dependencias, $this->_info_relaciones);
$diagrama = "digraph G {
rankdir=LR;
fontsize=8;
node [fontsize=6, fillcolor=white,shape=box, style=rounded,style=filled, color=gray];
";
if (isset($titulo)) {
$diagrama .= "label=\"$titulo\";\n";
}
foreach ($grafo->getNodes() as $nodo) {
$datos = $nodo->getData();
//Se determina la tabla
$id_tabla = $datos['identificador'];
$tabla = $this->_dependencias[$id_tabla];
//Se incluye el javascript para poder dumpear los datos de la tabla
$var_tabla = $id_tabla.self::$debug_pasadas;
echo toba_js::abrir();
echo "var $var_tabla = ".toba_js::arreglo($tabla->get_filas(null, true, false), true).";\n";
echo toba_js::cerrar();
//Se incluye la tabla como nodo
$label = "$id_tabla (".count($tabla->get_id_filas(false)).")";
$diagrama .= "$id_tabla [label=\"$label\",".
//Esta truchada es para arreglar otra ceguera del IE
"URL=\"javascript: padre=(window.parent.var_dump)? window.parent : window; padre.var_dump(padre.$var_tabla)\"];\n";
$diagrama .= $this->dump_esquema_relaciones($nodo);
}
$diagrama .= "}";
$parametros = array('contenido' => $diagrama, 'formato' => 'svg', 'es_dirigido' => 1);
$indice = uniqid();
toba::memoria()->set_dato_instancia($indice, $parametros);
$url = toba::vinculador()->get_url(toba_editor::get_id(), '1000045', array('esquema' => $indice),
array('validar' => false, 'celda_memoria' => 'debug'));
toba_ei_esquema::generar_sentencia_incrustacion($url, 'svg', "100%", "200px");
}
/**
* @ignore
*/
protected function dump_esquema_relaciones($nodo)
{
$datos = $nodo->getData();
$diagrama = '';
foreach ($nodo->getNeighbours() as $nodo_vecino) {
$datos_vecino = $nodo_vecino->getData();
//Busco los toba_relacion_entre_tablas correspondientes
$hijo_id = $datos_vecino['identificador'];
$padre_id = $datos['identificador'];
$relacion = $this->_relaciones[$padre_id."-".$hijo_id];
$mapeo = $relacion->get_mapeo_filas();
//Incluyo el mapeo en JS para poder dumpearlo
$var_mapeo = $padre_id."_".$hijo_id.self::$debug_pasadas;
echo toba_js::abrir();
echo "var $var_mapeo = ".toba_js::arreglo($mapeo, true).";\n";
echo toba_js::cerrar();
//Calculo la cantidad de filas padres e hijas involucradas en la relación
$cant_padres = 0;
$cant_hijos = 0;
$mapeo_hijos = array();
foreach ($mapeo as $padre => $hijos) {
if (count($hijos) > 0) {
$cant_padres++;
}
$mapeo_hijos = array_merge($mapeo_hijos, $hijos);
}
$cant_hijos = count(array_unique($mapeo_hijos));
//Incluyo la relación
$diagrama .= $padre_id . " -> " . $hijo_id .
" [fontsize=6,color=gray, label=\"$cant_padres - $cant_hijos\"".
//Esta truchada es para arreglar otra ceguera del IE
",URL=\"javascript: padre=(window.parent.var_dump)? window.parent : window;padre.var_dump(padre.$var_mapeo)\"];\n";
}
return $diagrama;
}
/**
* Retorna el orden hacia adelante en el cual se deben sincronizar las tablas
* El orden predeterminado es el orden topologico de las tablas
* @return array Arreglo id_tabla => toba_datos_tabla
*/
function orden_sincronizacion()
{
if ($this->_info_estructura['sinc_orden_automatico']) {
//-- Se construye el orden topológico
$sorter = new Structures_Graph_Manipulator_TopologicalSorter();
$deps = $this->get_tablas_activas();
$rel = $this->get_relaciones_activas();
$grafo = self::grafo_relaciones($deps, $rel);
$parciales = $sorter->sort($grafo);
$ordenes = array();
for ($i =0; $i<count($parciales) ; $i++) {
for ($j=0; $j<count($parciales[$i]); $j++) {
$ordenes[] = $parciales[$i][$j]->getData();
}
}
$tablas = array();
foreach ($ordenes as $orden) {
$tablas[$orden['identificador']] = $this->_dependencias[$orden['identificador']];
}
return $tablas;
} else {
//-- Se toma el orden natural en el cual se definieron las tablas
$ordenes = $this->get_tablas_activas();
$tablas = array();
foreach ($ordenes as $orden) {
$tablas[$orden['identificador']] = $this->_dependencias[$orden['identificador']];
}
return $tablas;
}
}
/**
* Retorna el orden hacia adelante en el cual se deben cargar las tablas
* Por defecto es el mismo que el orden de sincronización
* @return array Arreglo id_tabla => toba_datos_tabla
*/
function orden_carga()
{
return $this->orden_sincronizacion();
}
/**
* Retorna un grafo representando un conjunto de tablas y sus relaciones
* @return Structures_Graph
*/
static function grafo_relaciones($tablas, $relaciones)
{
$grafo = new Structures_Graph(true);
// Se construyen los nodos
$obj = array();
$nodo = null;
foreach ($tablas as $tabla) {
unset($nodo);
$nodo = new Structures_Graph_Node();
$proveedor = isset($tabla['objeto_proveedor']) ? $tabla['objeto_proveedor'] : $tabla['objeto'];
$obj[$proveedor] = $nodo;
$nodo->setData($tabla);
$grafo->addNode($obj[$proveedor]);
}
//Se agregan los arcos
foreach ($relaciones as $asoc) {
$padre = $asoc['padre_objeto'];
$hijo = $asoc['hijo_objeto'];
$obj[$padre]->connectTo($obj[$hijo]);
}
return $grafo;
}
//-------------------------------------------------------------------------------
//-- Servicios basicos
//-------------------------------------------------------------------------------
/**
* Retorna los identificadores de los datos_tabla incluídos en la relación
* @return array
*/
function get_lista_tablas()
{
return array_keys($this->_dependencias);
}
/**
* Retorna una referencia a una tabla perteneciente a la relación
* @param string $tabla Id. de la tabla en la relación
* @return toba_datos_tabla
*/
function tabla($tabla)
{
if($this->existe_tabla($tabla)){
return $this->_dependencias[$tabla];
}else{
toba_logger::instancia()->error("El datos_tabla '$tabla' solicitado no existe.");
throw new toba_error_def('El datos_tabla solicitado no existe o no esta asignado.');
}
}
/**
* Retorna las tablas de una relación
* @return array de toba_datos_tabla
*/
function get_tablas()
{
return $this->_dependencias;
}
/**
* Retorna las tablas que están habilitadas para la carga y la sincronización
* @return array de toba_datos_tabla
*/
function get_tablas_activas()
{
if (empty($this->_tablas_inactivas)) {
return $this->_info_dependencias;
} else {
$tablas_activas = array();
foreach ($this->_info_dependencias as $indx => $dep) {
if (! in_array($dep['identificador'], $this->_tablas_inactivas)) {
$tablas_activas[] = $dep;
}
}
return $tablas_activas;
}
}
/**
* Retorna relaciones de las tablas que están habilitadas para la carga y la sincronización
* @return array de toba_datos_tabla
*/
function get_relaciones_activas()
{
if (empty($this->_tablas_inactivas)) {
return $this->_info_relaciones;
} else {
$relaciones_activas = array();
foreach ($this->_info_relaciones as $indx => $rel) {
if (! in_array($rel['padre_id'], $this->_tablas_inactivas) && ! in_array($rel['hijo_id'], $this->_tablas_inactivas)) {
$relaciones_activas[] = $rel;
}
}
return $relaciones_activas;
}
}
/**
* Determina si una tabla es parte de la relación
* @param string $tabla Id. de la tabla en la relación
* @return boolean
*/
function existe_tabla($tabla)
{
return $this->dependencia_cargada($tabla);
}
/**
* Retorna al estado inicial todas las tablas incluídas
* Para volver a utilizar estas tablas se debe cargar nuevamente la relación con datos
*/
function resetear()
{
foreach($this->_dependencias as $dependencia){
$dependencia->resetear();
}
$this->_cargado = false;
}
/**
* Asegura que ningún cursor de alguna tabla se encuentre posicionado en ninguna fila específica
*/
function resetear_cursores()
{
foreach($this->_dependencias as $dependencia){
$dependencia->resetear_cursor();
}
}
/**
* Ventana para validaciones específicas, se ejecuta justo antes de la sincronización
* @ventana
*/
protected function evt__validar(){}
/**
* Valida cada una de las tablas incluídas en la relación
*/
function disparar_validacion_tablas()
{
foreach($this->_dependencias as $dependencia){
$dependencia->validar();
}
}
/**
* Retorna la estructura de datos utilizada por las tablas para mantener registro del estado de sus datos
* @return array
*/
function get_conjunto_datos_interno()
{
foreach($this->_dependencias as $id => $dependencia){
$datos[$id] = $dependencia->get_conjunto_datos_interno();
}
return $datos;
}
//-------------------------------------------------------------------------------
//-- PERSISTENCIA -------------------------------------------------------------
//-------------------------------------------------------------------------------
/**
* Retorna una referenca al Adm.Persistencia de la relación
* @return toba_ap_relacion_db
*/
function persistidor()
{
if (!isset($this->_persistidor)) {
//Se incluye el archivo
$particular = ($this->_info_estructura['ap'] == 3);
if ($particular && isset($this->_info_estructura['ap_archivo']) && isset($this->_info_estructura['ap_clase']) ) {
$clase = $this->_info_estructura['ap_clase'];
if( ! class_exists($clase) ) {
$punto = toba::puntos_montaje()->get_por_id($this->_info_estructura['punto_montaje']);
$path = $punto->get_path_absoluto().'/'.$this->_info_estructura['ap_archivo'];
require_once($path);
}
} else {
$clase = "toba_ap_relacion_db";
}
$this->_persistidor = new $clase( $this );
if ($this->_info_estructura['sinc_susp_constraints']) {
$this->_persistidor->retrasar_constraints();
}
$this->_persistidor->set_lock_optimista($this->_info_estructura['sinc_lock_optimista']);
}
return $this->_persistidor;
}
/**
* @deprecated usar persistidor() a secas
*/
function get_persistidor()
{
return $this->persistidor();
}
/**
* Utiliza la carga por clave del administrador de persistencia
* Carga la tabla raiz de la relación y a partir de allí ramifica la carga a sus relaciones
* @param array $clave Arreglo asociativo campo-valor por el cual filtrar la relación, si no se explicita se cargan todos los datos disponibles
* @return boolean Falso, si no se encontraron registros
*/
function cargar($clave=array())
{
//ATENCION: hay que controlar el formato de la clave
$this->log('*** Inicio CARGAR ****************************');
$ap = $this->persistidor();
if($ap->cargar_por_clave($clave) === true){
$this->log("*** Fin CARGAR (OK) *************************");
return true;
}else{
$this->log("*** Fin CARGAR (No se cargaron datos) ***************");
return false;
}
}
/**
* La relacion ha sido cargada con datos?
* @return boolean
*/
function esta_cargada()
{
return $this->_cargado;
}
/**
* Notifica a la relacion que sus tablas han sido o no cargadas
* @param boolean $cargado
*/
function set_cargado($cargado)
{
$this->_cargado = $cargado;
}
/**
* Fuerza a que los datos_tabla contenidos marquen todos sus filas como nuevas
* Esto implica que a la hora de la sincronización se van a generar INSERTS para todas las filas.
* Se utiliza para forzar una clonación completa de los datos una relación.
*/
function forzar_insercion()
{
foreach($this->_dependencias as $id => $dependencia){
$dependencia->forzar_insercion();
}
}
/**
* Sincroniza los cambios con el medio de persistencia
*/
function sincronizar($usar_cursores=false)
{
if (!$usar_cursores) {
$this->disparar_validacion_tablas();
$this->evt__validar();
$this->persistidor()->sincronizar();
//Se notifica el fin de la sincronización a las tablas
foreach ($this->_dependencias as $dependencia) {
$dependencia->notificar_fin_sincronizacion();
}
} else {
//Se sincroniza con cursores
foreach ($this->_dependencias as $dependencia) {
$filas = $dependencia->get_id_filas_filtradas_por_cursor(true);
if($filas) {
$dependencia->validar($filas);
}
}
$this->evt__validar();
$this->persistidor()->sincronizar($usar_cursores);
foreach ($this->_dependencias as $dependencia) {
$filas = $dependencia->get_id_filas_filtradas_por_cursor(true);
if($filas) {
$dependencia->notificar_fin_sincronizacion($filas);
}
}
}
}
/**
* Sincroniza los cambios con el medio de persistencia
*/
function sincronizar_filas($filas_tablas)
{
foreach ($this->_dependencias as $id => $dependencia) {
if (isset($filas_tablas[$id])) {
$dependencias->validar($filas_tablas[$id]);
}
}
$this->evt__validar();
$this->persistidor()->sincronizar(false, $filas_tablas);
//Se notifica el fin de la sincronización a las tablas
foreach ($this->_dependencias as $id => $dependencia) {
if (isset($filas_tablas[$id])) {
$dependencias->notificar_fin_sincronizacion($filas_tablas[$id]);
}
}
}
/**
* Elimina y sincroniza en el medio de persistencia todos los datos cargados en la relación
*/
function eliminar_todo()
{
$this->persistidor()->eliminar_todo();
$this->resetear();
}
/**
* Usar eliminar_todo, es más explícito
* @deprecated Desde 0.8.4, usar eliminar_todo, es más explícito
* @see eliminar_todo()
*/
function eliminar()
{
toba::logger()->obsoleto(__CLASS__, __METHOD__, "0.8.4", "Usar eliminar_todo");
$this->eliminar_todo();
}
/**
* Retorna el id de las tablas que no tienen padres en la relación
* @return array
*/
function get_tablas_raiz()
{
return $this->_tablas_raiz;
}
/**
* Fuente de datos que utiliza el objeto y sus dependencias
* @return string
*/
function get_fuente()
{
return $this->_info["fuente"];
}
/**
* Determina si los datos cargados difieren de los datos existentes en el medio de persistencia
* @return boolean
*/
function hay_cambios()
{
$hay_cambios = false;
foreach ($this->_dependencias as $dependencia) {
if ($dependencia->hay_cambios()) {
return true;
}
}
return false;
}
function get_columnas_tabla_padre($datos)
{
$resultado = array();
foreach($this->_info_columnas_asoc_rel as $info_rel){
if ($info_rel['asoc_id'] == $datos['asoc_id'] && $info_rel['padre_objeto'] == $datos['padre_objeto']){
$resultado[] = $info_rel['col_padre'];
}
}
return $resultado;
}
function get_columnas_tabla_hija($datos)
{
$resultado = array();
foreach($this->_info_columnas_asoc_rel as $info_rel){
if ($info_rel['asoc_id'] == $datos['asoc_id'] && $info_rel['hijo_objeto'] == $datos['hijo_objeto']){
$resultado[] = $info_rel['col_hija'];
}
}
return $resultado;
}
/**
* Carga en el nodo xml los datos cargados en el DR. Funciona sólo para relaciones que se modelan como un árbol, no grafos.
* @param SimpleXMLElement $xml Es el nodo XML donde se van a cargar todos los datos
*/
function get_xml($xml){
// Controla que haya una única tabla raiz
if(count($this->_tablas_raiz) != 1)
throw new toba_error_def('El datos_relacion no posee una única tabla raiz.');
// Recupera los registros de la tabla raiz para armar cada unidad del XML.
$datos_raiz = $this->_dependencias[$this->_tablas_raiz[0]]->get_filas();
// Para cada registro agrega el nodo XML correspondiente y manda a armar el contenido de cada uno
foreach($datos_raiz as $clave => $valor){
$entidad = $xml->addChild($this->_tablas_raiz[0]);
$this->armar_xml($entidad,$this->_tablas_raiz[0],$clave);
}
}
/**
* Arma un nodo XML para un registro de un datos tabla, con sus columnas como atributos y sus registros de tablas hijas como nuevos nodos internos
* Es un método recursivo con la siguiente estructura:
* a) Setea el cursor en el registro dado de la tabla dada
* b) agrega los datos del registro en el que se está parado como atributos del nodo xml recibido
* c) Para cada tabla hija agrega un nodo al nodo dado.
* d) Para cada registro de cada tabla hija, agrega un nodo al nodo creado en c) y llama recursivamente a la función
*
* @param SimpleXMLElement $xml es el nodo donde se va a agregar la información
* @param string $tabla la tabla de la que se van a sacar los datos
* @clave int $clave es la clave del registro de la tabla del que se van a sacar los datos
*/
protected function armar_xml($xml,$tabla,$clave)
{
// Setea el cursor de la tabla (esto además está seteando un cursor en las tablas hijas
$this->_dependencias[$tabla]->set_cursor($clave);
// Agrega los datos del registro seleccionado como atributos
$this->_dependencias[$tabla]->get_xml($xml);
// Recupera las tablas hijas de la tabla que se está recorriendo
$tablas_hijas = $this->get_tablas_hijas($tabla);
// Para cada tabla hija, agrega un nodo al nodo dado
foreach($tablas_hijas as $tabla_hija){
$id_filas_hijas = $this->_dependencias[$tabla_hija]->get_id_filas();
$xml2 = $xml->addChild($tabla_hija);
// Para cada registro de las tablas hijas seleccionado según el cursor, agrego un nodo y llamo recursivamente
foreach($id_filas_hijas as $id_fila_hija){
$xml3 = $xml2->addChild('registro');
$this->armar_xml($xml3,$tabla_hija,$id_fila_hija);
}
}
}
/**
* Dada una tabla del DR, recupera los identificadores de las tablas hijas
* @param string $tabla es el identificador de la tabla
* @return mixed es el conjunto de identificadores de las tablas hijas
*/
protected function get_tablas_hijas($tabla)
{
// Busco el id de la tabla
$id_objeto_padre = null;
$i = 0;
while(!$id_objeto_padre && $i < count($this->_info_dependencias)){
if($this->_info_dependencias[$i]['identificador'] == $tabla){
$id_objeto_padre = $this->_info_dependencias[$i]['objeto'];
}
$i++;
}
// Controlo que se haya encontrado la tabla
if(!$id_objeto_padre){
toba_logger::instancia()->error("No se puede obtener el conjunto de tablas hija de la tabla $tabla, que no pertenece a la relación.");
throw new toba_error_def('La tabla no pertenece a la relación, revise el log');
}
// Busco todos los id de objeto de las tablas hijas
$objetos_hijos = array();
foreach($this->_info_columnas_asoc_rel as $relacion){
if($relacion['padre_objeto'] == $id_objeto_padre){
$objetos_hijos[] = $relacion['hijo_objeto'];
}
}
// convierto los id de objetos en nombres de tablas
$tablas_hijas = array();
for($i = 0; $i < count($this->_info_dependencias); $i++){
if(in_array($this->_info_dependencias[$i]['objeto'],$objetos_hijos)){
$tablas_hijas[] = $this->_info_dependencias[$i]['identificador'];
}
}
return $tablas_hijas;
}
}
?>