New question

Question:

Date: 19-06-2015 10:42:46 (In Spanish)

ORM Propel: Crear objetos automáticos con fromArray[Resolved]

Hola comunidad, nuevamente necesito de ustedes. El orm de propel cuando crea las clases que le corresponden a cada tabla de la BD le pone un método llamado fromArray, este lo que hace es que si le pasamos como parámetro un arreglo que tenga como índice el nombre de los campos de la BD entonces devuelve el objeto con los valores, es muy cómodo a la hora de crear los objetos pq si en el html le ponemos en el name de los input el mismo nombre que tiene ese campo en BD entonces en el php se reduce a esto(supongamos que queremos crear una persona):
$persona = new Persona();
$persona->fromArray($_POST);


Ahora bien, mi problema es que tengo un formulario de buscar(supongamos que queremos buscar a una persona), entonces no tenemos que llenar todos los campos, pq puede ser que queramos buscar a todas las personas que se llaman 'Juan', o que tengan como primer apellido 'Rodriguez'. El problema es que cuando el campo que se llena es numérico como pude ser el número de hijos, por ejemplo, si dejamos ese campo vacío en la vista cuando creamos el objeto con el método fromArray en ese campo pone como valor por defecto 0, por lo tanto cuando realizamos la búsqueda no se obtienen los valores reales, ya que si solo queremos buscar las personas que se llaman 'Juan' realmente estaremos buscando a las personas que se llaman 'Juan' y tienen 0 hijos. Me explico?, Necesito por favor, su ayuda.

Gracias.
Tags: MySQL Developing - object oriented programming - OOP - ORM - ORM Propel - Question Votes: 0 - Answers: 3 - Views: 13 Share on: Google Facebook Twitter LinkedIn Link
 

Answers:

  • Date: 20-06-2015 05:32:44 Hola Jaime, a ver si entiendo, tu hidratas el objeto de negocio con fromArray y luego lo usas para hacer una busqueda? por que no haces la busqueda directamente con los objetos del modelo?

    Creo que seria algo así:
        $query=new PersonaQuery()
        $resultado = $query->findByFirstName('Juan');


    Creo que Propel crea métodos mágicos por cada columna (no estoy seguro) al estilo findByNOMBRECOLUMNA

    Luego me cuentas como te fue.

    Saludos,

    PD: digo "Creo que" muchas veces porque como te comente en otra oportunidad yo utilizo Doctrine como ORM, Propel "lo toco de oído" (o sea, poco y nada).
      Votes: 1 - Link answer
     
  • Date: 23-06-2015 04:25:51 Hola Fernando, tienes razón en lo que dices, pero realmente hay más cosas detrás de esto. Ya resolví pero voy a poner aquí la solución pq quizás a otros les pueda servir.

    Propel crea como bien dices un método por cada columna de la BD, pero además crea un método llamado "filterByArray" donde le puedes pasar un array cuyos índices sean el nombre de las columnas y también puedes buscar el elemento que quieres.

    Buscando tener que programar lo menos posible he creado un clase a la que le Specification para ahí poner los datos que necesito para buscar. La clase sería la siguiente:
    class BaseSpecification
    {
        private $_conditions;
    
       
        function __construct(array $arrConditions=array())
        {
           $this->_conditions=$arrConditions;
        }
    
       
        function getConditions()
        {
            // TODO: Implement getConditions() method.
            return $this->_conditions;
        }
    
        /**
         * Agrega una condición al arreglo de condiciones.
         *
         * @param string $index índice al que se quiere agregar la condición.
         * @param string|int $value valor que se quiere agregar a la condicion.
        */
        function setCondition($index, $value)
        {
            $this->_conditions[$index]=$value;
        }
    
        /**
         * Dada una entidad crea una especificación de esa entidad.
         *
         * @param mixed $entidad.
         * @return BaseSpecification.
         */
        static function FactorySpecification($entidad)
        {
            $nombreSpecification = get_class($entidad)."Specification";
            return new $nombreSpecification($entidad);
        }
    }
    


    Entonces cuando quiero buscar una entidad en BD, por ejemplo, voy a buscar una provincia, que solamente tiene un id y el nombre, creo una ProvinciaSpecification de la siguiente manera:

    class ProvinciaSpecification extends BaseSpecification
    {
        /**
          * Crea la especificacion.
          * @param Provincia $entidad.
         */
        function __construct($entidad = null)
        {
            parent::__construct();
    
            if($entidad!==null)
            {          
                if($entidad->getId() !== null  && $entidad->getId() !== "") 
                   {$this->setId($entidad->getId());}
    
                if($entidad->getNombrePro() !== null  && $entidad->getNombrePro() !== "") 
                    {$this->setNombrePro($entidad->getNombrePro());}
            }
        }
    
        function setId($v) {$this->setCondition("Id",$v);}
        function setNombrePro($v) {$this->setCondition("NombrePro",$v);}
    }
    


    Aquí es donde yo necesitaba crear el objeto que viene de la vista con el método fromArray, para no tener que ir agregando cada uno de los parámetros por los que se desea buscar.
    Les pongo el método fromArray para el objeto Provincia para que vean cómo es:

    public function fromArray($arr, $keyType = BasePeer::TYPE_PHPNAME)
    	{
    		$keys = ProvinciaPeer::getFieldNames($keyType);
    
    		if (array_key_exists($keys[0], $arr)) $this->setId($arr[$keys[0]]);
    		if (array_key_exists($keys[1], $arr)) $this->setNombrePro($arr[$keys[1]]);
    	}
    


    El problema es que en los método "setId" y "setNombrePro" que genera el propel en las entidades cuando le pasas una cadena vacía entonces pone un valor por defecto, en el caso de ser un campo de tipo int el valor que pone es 0, como expliqué anteriormente.

    Como ven el método fromArray lo que hace es buscar en el arreglo que le dimos, en este caso el $_POST, si un determinado índice existe, si existe entonces le agrega el valor al objeto. No basta en el html dejar el campo vacío pq cuando hacemos submit al formulario llega con un valor vacío y entonces al final el objeto se crea con todos los valores por defecto como ya he explicado y por supuesto ningún objeto cumple con esa condición en BD. Entonces la solución que le dí fue que el campo que no tiene datos en el html no se envía en el submit. Para esto lo que hice fue crear un método en javascript que será ejecutado en el evento onblur de los inputs, los selects, etc., que le quita el name de los elementos html para que no se envíen. Les pongo el código a continuación.

    <select onblur="quitarName(this,'ProvinciaPis')" id="ProvinciaPis">
        <option value="">Seleccionar...</option>
        <option value="2">Provincia2</option>
        <option value="3">Provincia3</option>
        <option value="4">Provincia4</option>
        <option value="5">Provincia5</option>
    </select>
    
    <script type="text/javascript">
        function quitarName(input,name){
            var texto=input.value;
    
            if(texto!=""){
                input.name=name;
            }
            else{
                input.name="";
            }
        }
    
    </script>
    


    Así funciona perfectamente como necesito. Espero que les sirva.

    Saludos.
      Votes: 1 - Link answer
     
  • Date: 23-06-2015 05:41:53 Jaime, me alegro que hayas logrado solucionar tu problema y muchas gracias por documentar tus solución tan claramente.

    Saludos,
      Votes: 0 - Link answer
     
To actively participate in the community first must authenticate, enter the system.Sign In