Error en foreach Invalid argument supplied for foreach()

publicado por: Anonymous

estoy recorriendo un array de datos con un foreach, pero a la hora de recorrerlo me suelta esto Invalid argument supplied for foreach() y me dice que las variables estan indefinidas. Este es mi codigo:

<?php 

include 'Models.php';

class Restaurant extends Models{
    private $datos;

    public function __construct(){
        $this->datos=array();
        parent::__construct();
    }

    public function InfoRest(){

        session_start();
        $id = $_SESSION['usuario']['id_usuario'];
        $sql = $this->pdo->prepare("SELECT * FROM restaurants WHERE id_usuario = '$id'");
        $sql->execute();
        if($sql->rowCount()>=1){
            while($row=$sql->fetch()){
                $this->datos[]=$row;
            }
        return $this->datos;
        }else{
            $sql->errorInfo()[2];
        }
    }
}
?>

$obj = new Restaurant();
$values = $obj->InfoRest();
 foreach($values as $value){

 }

<?php echo $value['name_rest'] ?>

Al recorrelo me arroja esos errores. Le he dado muchisimas vueltas pero no logro aun solucionar.
He hecho var_dump en el execute y me suelta true,y en el mismo proyecto tengo algo hecho de la misma forma y no arroja error, por ejemplo esto:

     class Models{

     protected $pdo;
     private $datos;

     public function __construct(){
        $this->datos=array();
        try{ 
            $this->pdo = new 
     PDO('mysql:host=localhost;dbname=vmenu.us;charset=utf8','root','');
            }
            catch(PDOExcepcion $e)
            { 
                echo $e->getMessage(); 
            exit; 
            }
      }

     public function DetailsRestaurant($id){

        $sql = $this->pdo->prepare("SELECT * FROM restaurants WHERE id_restaurant = :id");
        $sql->bindParam(':id',$id);
        $sql->execute();
        if($sql->rowCount()>=1){
            while($row = $sql->fetch()){
            $this->datos[]=$row;
            }
            return $this->datos;
        }else{
            $sql->errorInfo()[2];
        }

    }
 }

Y luego esto en mi Vista:

 $obj = new Models();
 $id = $_GET['id_restaurant'];
 $details = $obj->DetailsRestaurant($id);
  foreach($details as $result){
 }

 <?php echo $result['name_rest'] ?>

Como ven es lo mismo

solución

Hay un error de planteamiento en tu función.
Si quieres verificar que el usuario existe, no necesitas el uso de numRows, sino que puedes llenar tu array directamente.

Como en el else puedes retornar el mensaje de error, entonces puedes verificar si el array está vacío en el destino.

La función podría quedar así (la he blindado contra inyección SQL).

public function InfoRest(){

    session_start();
    $id = $_SESSION['usuario']['id_usuario'];
    $sql = $this->pdo->prepare("SELECT * FROM restaurants WHERE id_usuario = ?");
    $arrParams=array($id);
    $sql->execute($arrParams);

    if($sql){
        while($row=$sql->fetch()){
            $this->datos[]=$row;
        }
        return $this->datos;
    }else{
        return $sql->errorInfo()[2];
    }
}

Y en el código para leerla:

$obj = new Models();
 $id = $_GET['id_restaurant'];
 $details = $obj->DetailsRestaurant($id);
 print_r($details);

 foreach($details as $result){
      echo $result['name_rest'];
 }

NOTA: En InfoRest yo implementaría otra forma más lógica de devolver los posibles errores, que me permita verificar al recibir los datos si hay alguna clave con error.

En una futura edición de la respuesta podría proponer esa solución si te interesa. No lo hice aquí para no alejarme demasiado de tu código entrando en otros asuntos. La idea es escribir un código que sea coherente.

Si no te interesa en este caso el mensaje de error, puedes hacer lo siguiente:

    if($sql){
        while($row=$sql->fetch()){
            $this->datos[]=$row;
        }
        return $this->datos;
    }else{
        return NULL;
    }

De ese modo, tanto si no hay datos, como si la consulta falla, retornará NULL y al recibir los datos sólo tienes que evaluar la variable:

 $obj = new Models();
 $id = $_GET['id_restaurant'];
 $details = $obj->DetailsRestaurant($id);

 if($details){
      foreach($details as $result){
          echo $result['name_rest'];
      }
 }else{
     echo "No se encontraron datos o la consulta falló";
 }

Si te interesa mostrar al usuario posibles mensajes de errores de la consulta, entonces tendremos tres posibles resultados:

  1. Que la consulta no arroje datos
  2. Que haya un error en la consulta
  3. Que la consulta arroje datos

Una forma coherente de programar aquí sería devolver en todos los casos un array que podría ser NULL, tener el mensaje de error con una clave llamada error o un array con nuestros datos.

Dado que aquí me parece que la consulta no arrojará demasiadas filas, creo que podemos usar fetchAll para simplificar. Así traemos todos los resultados en una variable $resultado. También se puede hacer como antes, con el while.

La función quedaría así:

public function InfoRest(){
    session_start();
    $id = $_SESSION['usuario']['id_usuario'];
    $sql = $this->pdo->prepare("SELECT * FROM restaurants WHERE id_usuario = ?");
    $arrParams=array($id);
    $sql->execute($arrParams);

    if($sql){
        $resultado=$sql->fetchAll(PDO::FETCH_ASSOC);
        $this->datos[]=$resultado;
        return $this->datos;
    }else{
        return array ('error'=>$sql->errorInfo()[2]);
    }
}

Y cuando recibes los datos, evalúas los tres posibles resultados así:

$obj = new Models();
$id = $_GET['id_restaurant'];
$details = $obj->DetailsRestaurant($id);

if(!$detail){
    echo "No se encontraron datos"; 
}elseif (array_key_exists('error', $detail){
    echo $detail['error']; //Imprimirá el mensaje de error  
}else{
      foreach($details as $result){
          echo $result['name_rest'];
      }
}
Respondido por: Anonymous

Leave a Reply

Your email address will not be published. Required fields are marked *