Herencia con ActiveRecord

Hola a todos.

A lo mejor es una pregunta tonta, pero no tengo muy claro cómo se reflejaría en las tablas de la base de datos una clase abstracta con subclases concretas, por ejemplo. Es que por lo que veo en el lilbro, la forma de trabajar es primero montar las tablas y luego trabajar con los modelos adaptándolos a esas tablas, y las relaciones más complejas entre clases no acabo de ver cómo se representan.

Estaba pensando, entre otras cosas, en lo de las clases abstractas y en aplicar el patrón estado para guardar información sobre un pedido (nuevo, empaquetado, enviado, recibido...).

Muchas gracias.

Comentarios

  • Saludos Skinner de verdad no he tenido la necesidad de hacer algo parecido pero debe funcionar recuerda que trabajamos con la POO osea herencia, clases abstractas, sobreescritura de metodo y todo lo que encierra este paradigma...

    Exitos...
  • edited 12:42
    Sí, sospecho que tiene que funcionar, pero como antes de trabajar con los modelos hay que crear la base de datos (que no es OO), quiero saber cómo crear las subclases, qué relaciones de clave foránea hay que poner para representar la herencia, etc.

    Seguramente hay una forma habitual de hacerlo, ahora no tengo tiempo, pero luego googlearé un poco.

    Bye!
  • edited 12:42
    He encontrado esto:

    <!-- m --><a class="postlink" href="http://www.abelgonzalez.com/entornosabiertos/modelando-subtipos-en-una-base-de-datos-relacional_p171.html">http://www.abelgonzalez.com/entornosabi ... _p171.html</a><!-- m -->

    Pero si alguien puede poner un ejemplo práctico o explicar si el resultado es el esperado en Kumbia, se lo agradecería.

    Gracias.
  • edited 12:42
    Para colocar las relaciones de llave foranea debes seguir las convenciones de los modelos, si diseñas tus tablas de acuerdo a estas convenciones Kumbia entendera como trabaja tu modelo.

    Puedes usar los metodos has_many, has_one, belongs_to para definir las asociaciones tambien.
  • edited 12:42
    Ok, gracias. Lo intentaré y cuento qué tal.
  • edited 12:42
    Hola, ahora que tengo algo de tiempo estoy haciendo pruebas con modelos y tablas y tengo un problema al intentar usar clases abstractas. Voy a poner un ejemplo, a ver si alguien puede echarme una mano.

    Supongamos que tenemos una empresa con empleados de dos tipos: currantes y directivos, y cada uno de ellos tiene su sueldo, que se calcula de distinta forma: los currantes tienen un sueldo base (supondremos que cada currante tiene el suyo, dependiendo del tiempo que lleve en la empresa o lo que sea) más las horas extra que haga, mientras que un directivo tendrá un sueldo base (sustancialmente mayor que el del currante) más un "plus de egoísmo".

    El modelo de clases en el que había pensado es el siguiente:

    EMPLEADO (clase abstracta)
    -nombre
    -sueldo_base
    +calcular_sueldo()
    #calcular_sobresueldo() --> Operación abstracta o bien devuelve 0


    CURRANTE (clase concreta)
    -horas_extra
    -precio_hora_extra
    -calcular_sobresueldo() --> Redefine la operación de la superclase devolviendo importe horas extra


    DIRECTIVO (clase concreta)
    -plus_egoismo
    -calcular_sobresueldo() --> Redefine la operación de la superclase devolviendo plus de egoismo


    La función calcular_sueldo() de Empleado devuelve la suma del sueldo base más lo que devuelva la función calcular_sobresueldo(), que en la clase Empleado puede ser abstracta o bien devolver 0.

    La función calcular_sobresueldo() de Currante devuelve el número de horas extra multiplicado por el precio de la hora extra, mientras que en la clase Directivo devuelve el plus de egoísmo.

    Hasta ahí no es más que un ejemplo sencillo de herencia y sobrecarga de funciones. El problema viene al intentar hacer las tablas para guardar esa información. Esto es lo que he hecho:

    empleado
    id: int (clave)
    nombre: char
    sueldo_base: float

    currante
    horas_extra: int
    precio_hora_extra: float
    empleado_id: int (clave foránea)

    directivo
    plus_egoismo: float
    empleado_id: int (clave foránea)

    Me he encontrado con varios problemas:
      * Parece que la clase abstracta no le ha gustado mucho a Kumbia, que me devuelve un error cuando intenta instanciarla en kumbia.php:110
    if&#40;!class_exists&#40;$objModel&#41;&#41;&#123;
      &#46;&#46;&#46;
    &#125;
    else &#123;
      self&#58;&#58;$models&#91;$objModel&#93; = new $objModel&#40;$model, false&#41;;
    &#125;
    
    [/list:u]
      * No consigo acceder al atributo nombre de Empleado desde Directivo o Currante (probablemente porque no he definido correctamente las tablas o me he dejado algo importante en los modelos que indique la herencia)[/list:u]
      * Cuando en una vista intento mostrar información sobre los empleados sólo consigo acceder a los datos de Empleado, el cálculo de los sobresueldos no se llega a hacer. Claro que parece lógico, porque accediendo a la información de la tabla empleado no doy ninguna instrucción para que se acceda también a las tablas directivo o currante[/list:u]

      Veo más o menos dónde están los errores, pero no encuentro la forma correcta de hacer esto en Kumbia. En el libro tampoco he encontrado ninguna referencia a clases abstractas ni a herencia aparte de los extends de ActiveRecord, ApplicationController...

      Perdón por el rollo y gracias por la ayuda.
  • edited 12:42
    He estado mirando cómo funciona en Ruby on Rails y he visto que el modelo que toman no es el de usar una tabla por cada subclase sino una genérica con todos los atributos de la superclase y de cada subclase y un campo "type" para diferenciarlas. En este caso habrá que ir con cuidado a la hora de poner nombres a los atributos para que no coincidan. No me acaba de quedar claro cómo se haría en una jerarquía de varios niveles con clases concretas. ¿type2, type3...?

    <!-- m --><a class="postlink" href="http://wiki.rubyonrails.org/rails/pages/Inheritance">http://wiki.rubyonrails.org/rails/pages/Inheritance</a><!-- m -->
    <!-- m --><a class="postlink" href="http://wiki.rubyonrails.org/rails/pages/SingleTableInheritance">http://wiki.rubyonrails.org/rails/pages ... nheritance</a><!-- m -->
    <!-- m --><a class="postlink" href="http://www.patchedsoftware.com/RailsEnvy-ActiveRecord.mov">http://www.patchedsoftware.com/RailsEnv ... Record.mov</a><!-- m --> (aproximadamente a las tres cuartas partes del vídeo hablan de relaciones polimórficas entre tablas)

    ¿Me equivoco o en Kumbia no hay implementada por ahora una solución a ese problema?
  • Puedes publicar el codigo de los modelos?

    Gracias
  • edited 12:42
    Hola, pego el código. He cambiado el sistema de tablas para hacerlo sólo con una que contenga la información de la superclase y de las dos subclases, junto con el campo "type":
    CREATE TABLE `empleado` &#40;
      `id` int&#40;10&#41; unsigned NOT NULL auto_increment,
      `nombre` varchar&#40;32&#41; NOT NULL default '',
      `sueldo_base` float NOT NULL,
      `type` varchar&#40;32&#41; NOT NULL,
      `num_horas_extra` int&#40;11&#41; default NULL,
      `precio_hora_extra` float default NULL,
      `plus_egoismo` float default NULL,
      PRIMARY KEY  &#40;`id`&#41;
    &#41;;
    
    insert into `empleado` values&#40;'1','Pepe','800','currante','15','12&#46;87',null&#41;,
     &#40;'2','Juan','900','currante','6','15',null&#41;,
     &#40;'3','Ricardo','850&#46;37','directivo',null,null,'350&#46;28'&#41;;
    
    El controlador "empleados_controller.php":
    &lt;?php
    	class EmpleadosController extends ApplicationController &#123;
    		function sueldo &#40;&#41; &#123;
    			$this-&gt;empleados = $this-&gt;Empleado-&gt;find&#40;&#41;;
    		&#125;
    		
    	&#125;
    ?&gt;
    
    El modelo "empleado.php":
    &lt;?php
    	abstract class Empleado extends ActiveRecord &#123;
    		
    		function calcular_sueldo&#40;&#41; &#123;
    			return $sueldo_base + $this-&gt;calcular_sobresueldo&#40;&#41;;
    		&#125;
    		
    		function calcular_sobresueldo&#40;&#41; &#123;
    			return 0;
    		&#125;	
    	&#125;
    ?&gt;
    
    El modelo "directivo.php":
    &lt;?php
    	include_once &quot;empleado&#46;php&quot;;
    	
    	class Directivo extends Empleado &#123;
    
    		function calcular_sobresueldo&#40;&#41; &#123;
    			return $this-&gt;plus_egoismo;
    		&#125;
    	&#125;
    ?&gt;
    
    El modelo "currante.php":
    &lt;?php
    	include_once &quot;empleado&#46;php&quot;;
    
    	class Currante extends Empleado &#123;
    		
    		function calcular_sobresueldo&#40;&#41; &#123;
    			return $this-&gt;horas_extra * $this-&gt;precio_hora_extra;
    		&#125;
    	&#125;
    ?&gt;
    
    Y la vista "empleados/sueldo.phtml":
    &lt;?php
    	foreach &#40;$empleados as $empleado&#41; &#123;
    		print $empleado-&gt;nombre&#46;&quot; &quot;&#46;$empleado-&gt;calcular_sueldo&#40;&#41;&#46;&quot;&lt;br&gt;&quot;;
    	&#125;
    ?&gt;
    

    Está claro que esto no funciona, en parte porque en ningún sitio le indico qué campos de la tabla "empleado" son de currante y cuáles de directivo. Pero el error que me da directamente al acceder a <!-- m --><a class="postlink" href="http://localhost/empresa/empleados/sueldo">http://localhost/empresa/empleados/sueldo</a><!-- m --> es el de que no puede instanciar el modelo "empleado" por ser abstracto, kumbia.php:110 (v0.4.6 RC6).

    Si quito lo de "abstract" en la clase "empleado", entonces el resultado que obtengo es:
    Pepe 0
    Juan 0
    Ricardo 0

    Del mismo modo, al crear un formulario para "empleado" me permite introducir todos sus campos (y los de las subclases), siempre que la clase no sea abstracta, pero al hacer un formulario para "currante" me dice, obviamente, que no existe la tabla "currante" en la base de datos.

    ¿Cómo puedo usar clases abstractas, subclases y polimorfismo?

    Gracias.
  • He estado revisando esto y la solucion que he encontrado es la siguiente:

    He colocado todas las clases en el mismo archivo models/empleado.php:

    No he probado si se puede colocar en varios archivos, supongo que no habria problema:
    class Empleado extends ActiveRecord &#123;
    
          protected $source = &quot;empleado&quot;;
          
          function calcular_sueldo&#40;&#41; &#123;
             return $sueldo_base + $this-&gt;calcular_sobresueldo&#40;&#41;;
          &#125;
          
          function calcular_sobresueldo&#40;&#41; &#123;
             return 0;
          &#125;   
    &#125;
    
    class Directivo extends Empleado &#123;
    
          protected $source = &quot;empleado&quot;;
    
          function calcular_sobresueldo&#40;&#41; &#123;
             return $this-&gt;plus_egoismo;
          &#125;
    &#125;
    
    class Currante extends Empleado &#123;
    
          protected $source = &quot;empleado&quot;;
          
          function calcular_sobresueldo&#40;&#41; &#123;
             return $this-&gt;horas_extra * $this-&gt;precio_hora_extra;
          &#125;
    &#125;
    
    

    Hasta aqui todo bien, la propiedad source le indica que trabaja con la tabla empleado, sin embargo ActiveRecord inicialmente no toma en cuenta source sino que da prioridad a el nombre de la clase. Ahora arreglamos esto en forms/db/active_record.php en el metodo model_name:
    private function model_name&#40;&#41;&#123;
                    if&#40;!$this-&gt;model&#41;&#123;
                                $this-&gt;source = get_class&#40;$this&#41;;
                    &#125;
                    if&#40;ereg&#40;&quot;&#40;&#91;a-z&#93;&#41;&#40;&#91;A-Z&#93;&#41;&quot;, $this-&gt;source, $reg&#41;&#41;&#123;
                            $this-&gt;source = str_replace&#40;$reg&#91;0&#93;, $reg&#91;1&#93;&#46;&quot;_&quot;&#46;strtolower&#40;$reg&#91;2&#93;&#41;, $this-&gt;source&#41;;
                    &#125;
                    $this-&gt;source = strtolower&#40;$this-&gt;source&#41;;
            &#125;
    

    Con esto funcionaria,

    Saludos[/code]
  • edited 12:42
    Muchas gracias! Voy a probarlo!
  • edited 12:42
    Pues no consigo cambios. Efectivamente, lo de $source parece que algo hace, aunque lo he tenido que poner como public en vez de protected, si no no me dejaba. Pero el resultado de la ejecución de la función es el mismo, da 0 para todos. Y sigue sin dejarme usar clases abstractas.

    Yo creo que lo que hace falta es que Kumbia dé un soporte nativo para las clases abstractas y el polimorfismo, parecido a lo que hace Rails con el campo "type" de las tablas de la bd. No digo que sea fácil, pero yo lo pondría entre las prioridades, todo lo relacionado con la orientación a objetos es básico para un framework de PHP5. Me ofrecería para hacerlo, pero la verdad es que no tengo el nivel suficiente de php. <!-- s:oops: --><img src="{SMILIES_PATH}/icon_redface.gif" alt=":oops:" title="Embarassed" /><!-- s:oops: -->
  • Que problemas has tenido?, Ayer lo he probado y me funciona bien. Puedes publicar cual es tu problema?
  • edited 12:42
    Bueno, no me da ningún error, pero el resultado que me devuelve sigue siendo

    Pepe 0
    Juan 0
    Ricardo 0

    Es decir, que no ejecuta la función polimórficamente en las subclases sino que para todas ejecuta la de la superclase, que devuelve 0.
  • Lo que sucede es que debes crear dinamicamente el objeto adecuado de acuerdo a su tipo. En el mismo ejemplo de ruby on rails puedes ver como lo hacen <!-- m --><a class="postlink" href="http://wiki.rubyonrails.org/rails/pages/SingleTableInheritance">http://wiki.rubyonrails.org/rails/pages ... nheritance</a><!-- m -->

    Aqui puedes utilizar un;
    new $&#123;Empleado-&gt;type&#125;&#40;&#41;;
    

    Gracias
  • edited 12:42
    Hola.

    Gracias por el tiempo, Andrés, de verdad. No acabo de entender lo de
    new $&#123;Empleado-&gt;type&#125;&#40;&#41;;
    

    De todos modos, puedo crear un Currante haciendo esto:
    $cur = new Empleado&#40;&#41;;
    $cur-&gt;type = &quot;currante&quot;;
    $cur-&gt;nombre = &quot;Pedro&quot;;
    $cur-&gt;sueldo_base=300;
    $cur-&gt;num_horas_extra=4;
    $cur-&gt;precio_hora_extra=10&#46;5;
    $cur-&gt;save&#40;&#41;;
    

    Eso funciona, aunque no me parece la mejor forma de crear una subclase, ya que ahí podría añadir tranquilamente atributos de Directivo junto con los de Currante. Lo lógico sería poder hacer new Currante() y que Kumbia crease un nuevo registro en la tabla Empleado con type="currante". No sé cómo se podría diferenciar los atributos que son de Currante, de Directivo y de Empleado para que funcionara el ActiveRecord correctamente e incluso para que el scaffold permitiera mostrar los atributos comunes de Empleado y los propios de cada subclase por separado.

    El problema ahora mismo es que no puedo hacer cosas como:
    $this-&gt;currantes = $this-&gt;Currante-&gt;find&#40;&#41;;
    &#91;error&#93; PHP Fatal error&#58;  Call to a member function find&#40;&#41; on a non-object
    

    porque no existe la tabla currante. Pero si lo dejo como:
    $this-&gt;empleados = $this-&gt;Empleado-&gt;find&#40;&#41;;
    

    Entonces al hacer en la vista:
    foreach &#40;$empleados as $empleado&#41; &#123;
    	print $empleado-&gt;nombre&#46;&quot; &quot;&#46;$empleado-&gt;calcular_sueldo&#40;&#41;&#46;&quot;&lt;br&gt;&quot;;
    &#125;
    

    ejecuta siempre estas dos funciones de Empleado:
    function calcular_sueldo&#40;&#41; &#123;
       return $this-&gt;sueldo_base + $this-&gt;calcular_sobresueldo&#40;&#41;;
    &#125;
         
    function calcular_sobresueldo&#40;&#41; &#123;
       return 5;
    &#125;
    

    Nunca se ejecuta el calcular_sobresueldo() de la clase Currante, que es lo que me interesaría.

    Gracias de nuevo.
  • Bueno aqui lo que debes hacer es, no llamar a modelos cuando no se traten de tablas directamente usando el operador new.
    $a = new Currante&#40;&#41;;
    

    Probablemente con el $this->Currante no funcione si no colocas una a una las clases en archivos por separado en models/

    De otro lado en PHP se pueden crear objetos dinamicamente usando el nombre de clase en alguna variable asi como estaba en el ejemplo de ruby on rails.
    $tipo = $empleado-&gt;type;
    $objeto = new $tipo&#40;&#41;;
    

    Si tipo es igual al nombre de la clase entonces creara el objeto indicado.

    Saludos
  • edited 12:42
    Hola, he estado fuera unos días y no he podido dedicarle tiempo, pero ahora he probado lo que dices. Lo de
    $this-&gt;currantes = $this-&gt;Currante-&gt;find&#40;&#41;;
    
    no funciona aunque separe las clases en archivos separados. Me da una excepción
    KumbiaException&#58; No existe la tabla 'currante' en la base de datos 'empresa'
    

    Y lo de hacer
    $tipo = $empleado-&gt;type;
    $objeto = new $tipo&#40;&#41;;
    
    lo entiendo pero no sé de qué sirve. Es decir, está bien para crear un objeto del mismo tipo que otro, pero el problema ahora mismo no es descubrir cómo se llama el tipo, que ya lo sé, sino que me permita crear un objeto de ese tipo, "sabiendo" Kumbia de algún modo que la información de Currante está definida dentro de la tabla de otra clase. Dicho de otro modo, igual que Kumbia identifica los campos llamados "id" y las claves foráneas, debería haber otra palabra reservada, "type", y que Kumbia supiera qué hacer cuando hay un campo con ese nombre, es decir, buscar un modelo con ese nombre y crear un objeto de esa clase.

    Los pasos para crear un objeto de una subclase serían algo así: cuando se haga new Currante(), Kumbia ve a través del "extends" que Currante es una subclase de otro modelo llamado Empleado; luego crea una instancia php de la clase Currante y al hacer un save() debería añadir un registro a la tabla empleado que contenga type="currante". Y por supuesto, debería permitirme hacer esto aunque la clase Empleado fuese abstracta.

    El principal problema estaría en saber indicarle qué campos de la tabla "empleado" son comunes para todos los empleados o propios de currante o directivo, porque yo podría hacer
    $currante-&gt;plus_egoismo = 30
    
    cuando el plus por egoísmo no pertenece a currante sino a directivo. Eso no tengo muy claro cómo lo hace Rails.

    Saludos!
  • Rails no soporta nativamente las clases abstractas, realmente hace lo mismo que kumbia, lo que sucede es que han definido en el ejemplo un campo type para luego a nivel de aplicación crear el objeto correcto:

    volvamos a <!-- m --><a class="postlink" href="http://wiki.rubyonrails.org/rails/pages/SingleTableInheritance">http://wiki.rubyonrails.org/rails/pages ... nheritance</a><!-- m -->:
    def new
      case @params&;#91;&#58;person_type&#93;
        when &quot;Manager&quot; 
          @person = Manager&#46;new
        when &quot;Slave&quot; 
          @person = Slave&#46;new
      end
    end
    

    El objeto es creado apartir de un campo cualquiera en este caso "type" que lo usan para internamente saber de que clase concreta es el objeto resultante.

    En Ruby se puede cambiar el objeto devuelto en un constuctor por eso, si esperas que:
    &lt;?php
    
      class Empleado extends ActiveRecord &#123;
                pùblic function __construct&#40;&#41;&#123;
                      if&#40;$this-&gt;type==&quot;Directivo&quot;&#41;&#123;
                          return new Directivo&#40;&#41;;
                      &#125;
                      if&#40;$this-&gt;type==&quot;Currante&quot;&#41;&#123;
                          return new Currante&#40;&#41;;
                      &#125;
                &#125;
      &#125;
    
    ?&gt;
    

    Sin embargo este codigo es invalido en PHP por lo tanto debes hacerlo:
    $tipo = $empleado-&gt;type; 
    $objeto = new $tipo&#40;&#41;;  
    

    No es crear un objeto del mismo tipo que otro, es si en $empleado->type es igual a "Currante" entonces $objeto = new $tipo(); creara un objeto de la clase correcta "Currante".

    Por lo demas puedes colocar las clases en el mismo archivo models/empleado.php

    Saludos
  • edited 12:42
    Hola.

    No me he rendido, no. Es que he andado liado.

    Creo que voy pillando por dónde vas, lo que pasa es que yo intentaba verlo de otra forma y por eso no entendía lo que me querías decir. Lo que yo quería hacer era un new Currante() y luego un save() para guardar el nuevo objeto en la BD (cosa que no iba a suceder), mientras que, por lo que entiendo, tú lo que haces es recuperar los Empleados guardados para luego crear un objeto dependiendo del tipo y poder trabajar con ese objeto. Pero en ese caso, no sólo tengo que crear el currante (o directivo), sino que tengo que pasarle todos los datos del empleado así, ¿no?
    foreach &#40;$this-&gt;empleados as $empleado&#41; &#123;
      $tipo = $empleado-&gt;type;
      $objeto = new $tipo&#40;&#41;;
      $objeto-&gt;nombre = $empleado-&gt;nombre;
      $objeto-&gt;sueldo_base = $empleado-&gt;sueldo_base;
      &#46;&#46;&#46;
    &#125;
    

    Tengo que decir que eso por fin ha hecho que me funcionara el polimorfismo (gracias!! <!-- s:D --><img src="{SMILIES_PATH}/icon_biggrin.gif" alt=":D" title="Very Happy" /><!-- s:D --> ), pero la verdad es que lo de copiar los campos es bastante feo, y además tendría que empezar a hacer ifs para diferenciar los campos de cada subclase o bien hacer que todos tengan todos los campos, que no sé qué es más feo. Y por otro lado, no puedo luego consultar los currantes haciendo algo como $this->Currante, que sería lo ideal, sino que tengo que añadir dentro del bucle algo como un array:
    $this-&gt;emps = Array&#40;&#41;;
    foreach &#40;&#46;&#46;&#46;&#41; &#123;
      &#46;&#46;&#46;
      $this-&gt;emps&#91;&#93; = $objeto;
    &#125;
    

    para poder luego consultarlos.

    Pero eso no me resuelve mi duda inicial: ¿y para crearlos? Es decir, ahora tengo un objeto Currante nuevo o modificado y lo tengo que almacenar en la base de datos. ¿Tengo que hacer el proceso inverso? O sea, crear un objeto Empleado, copiarle todos los atributos del Currante y luego hacer un save() del Empleado. No me convence demasiado...

    Bueno, te agradezco las explicaciones y el interés. Y déjame que insista en una cosa: ¿no se podría intentar que Kumbia automatizara todo esto de alguna forma, dándole algún tipo de instrucciones para que sepa cuándo una clase es subclase de otra y con el campo "tipo" hacer que almacene las cosas correctamente (incluidas clases abstractas)? Sería un reto, pero le daría más poder a Kumbia.

    Saludos a todos y gracias de nuevo!
  • Tienes razon, parece que la implementación manual no esta muy buena que digamos, asi que lo mejor es buscar una solución a nivel del framework.

    Voy a trabajar en ello para 0.5

    Saludos
  • edited 12:42
    Si la versión 0.5 incluye eso además del montón de novedades que ya tiene, tendremos que empezar a llamarla v0.5. <!-- s:lol: --><img src="{SMILIES_PATH}/icon_lol.gif" alt=":lol:" title="Laughing" /><!-- s:lol: -->

    En serio, sería un avance muy grande. Pero no lo veo muy fácil de implementar; lo que se gana por un lado se pierde por otro, hay mucha casuística y hay que tomar decisiones de diseño que luego a lo mejor no gustan a todos. Se me ocurren muchas dudas.

    Por ejemplo, si tenemos una jerarquía en la que la clase Persona tenga dos subclases, Empleado y Cliente, y que de Empleado a su vez cuelguen Currante y Directivo, ¿todas estas clases deberían compartir la misma tabla Empleado? ¿Y eso sería así para todas las subclases que se deriven de cualquiera de éstas? ¿Cómo se indica que un campo es de la superclase Empleado o bien de una subclase cualquiera perdida por la jerarquía?

    A lo mejor sería más fácil tener una tabla distinta para cada una de las subclases y otra con los atributos comunes, y que las demás se relacionen con ésta última con un campo id (caso 3 de esta explicación), pero habría que indicar de alguna forma que no es una relación asociativa sino de herencia. Lo del uso de tablas separadas es más parecido en lógica a la orientación a objetos, pero hay que consultar todas las tablas de la jerarquía de arriba abajo cada vez que se quieran conocer los atributos de una clase (parecido a como se haría a alto nivel), lo cual tampoco es muy deseable si esa jerarquía es muy grande. Pero si se hace todo en una única tabla se desperdiciaría mucho espacio en caso de jerarquías grandes.

    Más dudas: ¿cómo se sabe que dos tablas son "hermanas", es decir, que pertenecen a una misma jerarquía y no a dos distintas que cuelguen de la misma clase? ¿Haría falta? ¿Habría que crear un campo para indicar que una clase es abstracta o se haría a nivel de php?

    Un posible objetivo en el que se podría pensar es en hacer scaffolding de una clase abstracta, y que cambiando en un select box del formulario el tipo de subclase aparezcan para rellenar los campos de la clase seleccionada. Y si se cambia la selección por otra subclase, aparecen otros campos. Sería ideal para introducir datos de jerarquías. Por ejemplo, en una universidad quieren dar de alta a una persona, y sólo eligiendo con un clic entre Profesor o Estudiante aparecerían los campos específicos a rellenar. Si eso funcionase significaría que todo lo que hay por debajo es correcto.

    Está claro que de fácil no tiene nada, pero si puedo echar una mano, estaré encantado.

    Saludos!

    PD: Ahora que lo pienso, esto debería ir al subforo de nuevas funcionalidades. <!-- s:? --><img src="{SMILIES_PATH}/icon_confused.gif" alt=":?" title="Confused" /><!-- s:? -->
  • edited 12:42
    Aunque ya hace tiempo de este post, voy a explicaros mi experiencia con bases de datos orientadas a objetos. En mi trabajo usamos Caché de Intersystems. Aunque el lenguaje que usan no me gusta nada, ni muchas de sus funcionalidades, y menos que no es software libre,si hay que decir que tiene cosas interesantes.

    Al ser orientado a objetos, existe herencia, polimorfismo, etc.
    Para lograr esto, en Cache no se crean tablas, sino objetos que heredan de una superclase Persistent, la cual indica que este objeto será almacenado en disco (en nuestro caso habría de heredar de ActiveRecord):

    Class Persona extends %Persistent{
    Nombre As %String;
    Apellidos as %String;
    Edad as %Integer;
    etc
    }

    Class Estudiante as Persona{
    Escuela As %String;
    Curso As %String;
    etc
    }

    Pongamos que queremos crear una tabla por ejemplo Estudiante que hereda de Persona.

    En Persona tenemos los atributos básicos (nombre, edad, domicilio, etc). La tabla Estudiante tiene los atributos extras (escuela, curso, etc). Al crear la tabla Estudiante, se crea automáticamente un id que referencia a Persona.

    O sea, yo creo un estudiante:

    estudiante = New Estudiante();
    estudiante->nombre="Pepe";
    estudiante->edad="23";
    estudiante->curso="2º";
    etc

    Vamos, como cualquier lenguaje OOP.
    A la hora de buscar, hay que tener bien definidos los índices tanto para los id de Estudiante, como los de estudiante->persona que contenga.


    Me he inventado un poco el pseudocódigo pero creo que queda clara la idea.
Sign In or Register to comment.