Bonjour,
Voila je rencontre un petit problème avec mon code.
Dans le Tuto, dans le chapitre 12, a partir du temps de la video 35mn15sec, on a une erreur :
Le resultat de notre requette n'est pas un OBJET mais un TABLEAU
Tout cela est resolu de 35mn15sec à 37mn12sec
Je fais exactement la meme chose, mais à la fin, ma variable $post est toujours considérée comme un tableau et non comme un objet
Est ce que quelqu'un saurait d'ou ca peut venir ? Ca fait 2 heures que je cherche sans resultat :-(
Merci, et merci au createur de ce site !!
Ohhhh je viens de trouver
C'était un problème de casse
single.php - mauvais
$post = $db->prepare('SELECT * FROM articles WHERE id = ?', [$_GET['id']], 'APP\Table\Article', true);
single.php - corrigé
$post = $db->prepare('SELECT * FROM articles WHERE id = ?', [$_GET['id']], 'App\Table\Article', true);
Et il fallait appeller le namespace de cette facon : namespace App\Table;
plutôt que namespace APP\Table;
Vraiment, merci pour ton aide, ton message d'il y a 2 heures, quand tu parlais du single.php, et ton message sur la casse, m'ont mis sur la piste.
Génial! :-)
Bonsoir,
Oui, voici le code de mon côté :
Il y a 3 fichiers
Database.php
<?php
namespace App;
use \PDO;
class Database{
private $db_name;
private $db_user;
private $db_pass;
private $db_host;
private $pdo;
public function __construct($db_name, $db_user='root', $db_pass='', $db_host='localhost'){
$this->db_name=$db_name;
$this->db_user=$db_user;
$this->db_pass=$db_pass;
$this->db_host=$db_host;
}
private function getPDO(){
if($this->pdo === null){
$pdo = new PDO('mysql:dbname=blog;host=localhost','root','');
$pdo->setAttribute(PDO::ATTR_ERRMODE, PDO::ERRMODE_EXCEPTION);
$this->pdo = $pdo;
}
return $pdo;
}
public function query($statement, $class_name){
$req = $this->getPDO()->query($statement);
$datas = $req->fetchAll(PDO::FETCH_CLASS, $class_name);
return $datas;
}
public function prepare($statement, $attributes, $class_name, $one = false){
$req = $this->getPDO()->prepare($statement);
$req->execute($attributes);
$req->setFetchMode(PDO::FETCH_CLASS, $class_name);
if($one) {
$datas = $req->fetch();
} else {
$datas = $req->fetchAll();
}
return $datas;
}
}
single.php
<?php
$post = $db->prepare('SELECT * FROM articles WHERE id = ?', [$_GET['id']], 'APP\Table\Article', true);
var_dump($post);
?>
<h1><?= $post->titre; ?></h1>
<p><?= $post->contenu; ?></p>
index.php
<?php
require '../app/Autoloader.php';
App\Autoloader::register();
if(isset($_GET['p'])){
$p = $_GET['p'];
} else{
$p = 'home';
}
// initialisation des objets
$db = new App\Database('blog');
ob_start();
if($p === 'home'){
require '../pages/home.php';
} elseif ($p ==='article'){
require '../pages/single.php';
}
$content = ob_get_clean();
require '../pages/templates/default.php';
$req->setFetchMode(PDO::FETCH_CLASS, $class_name); se trouve dans la class Database.php
Salut,
Il y a une petite erreur dans getPDO()
:
la 1ère fois qu'on fait un getPDO()
,
$this->pdo
est null
, donc on créer $pdo
, on le "range" dans $this->pdo
, et on le retourne.
Ça fonctionne... Mais,
la 2ème fois qu'on fait un getPDO()
,
this->pdo
n'est PLUS null
, donc on ne créer PAS $pdo
, pourtant on essaie de le "retourner" à la fin. Absurde
Ce n'est pas $pdo
qu'il faut retourner, mais $this->pdo
;
Salut,
Merci pour ta remarque constructive! Effectivement, je ne faisais pas le bon return. Je viens de corriger cette partie.
Malgré celà, j'ai quand meme le même problème :
$post est considéré comme un "Array" plutot qu'un "object"
Voici un screenshot de la page Article dans le navigateur (issue de single.php) : http://jbrault.esy.es/php.jpg
Dans ta fonction prepare il faut que tu modifies un paramètre
EDIT : bon un codeshare.io car y'a un bug de syntaxe
Salut,
Merci pour l'amélioration du code, mais j'ai encore la même erreur
Database.php :
<?php
namespace App;
use \PDO;
class Database{
private $db_name;
private $db_user;
private $db_pass;
private $db_host;
private $pdo;
public function __construct($db_name, $db_user='root', $db_pass='', $db_host='localhost'){
$this->db_name=$db_name;
$this->db_user=$db_user;
$this->db_pass=$db_pass;
$this->db_host=$db_host;
}
private function getPDO(){
if($this->pdo === null){
$pdo = new PDO('mysql:dbname=blog;host=localhost','root','');
$pdo->setAttribute(PDO::ATTR_ERRMODE, PDO::ERRMODE_EXCEPTION);
$this->pdo = $pdo;
}
return $this->pdo;
}
public function query($statement, $class_name){
$req = $this->getPDO()->query($statement);
$datas = $req->fetchAll(PDO::FETCH_CLASS, $class_name);
return $datas;
}
public function prepare($statement, $attributes, $class_name, $one = false){
$req = $this->getPDO()->prepare($statement);
$req->execute($attributes);
if($class_name === null){
$req->setFetchMode(PDO::FETCH_OBJ);
}else {
$req->setFetchMode(PDO::FETCH_CLASS, $class_name);
}
if($one) {
$datas = $req->fetch();
} else {
$datas = $req->fetchAll();
}
return $datas;
}
}
Tu as quoi dans le var_dump ?
je t'ai mis un codeshare à la place à cause d'un bug de syntaxe
Merci pour le codeshare
Dans le var_dump, ca me donne toujours un array :
Je n'en suis pas sûr mais,
peut-être qu'il faut faire le execute
après le setFetchMode
.
Et toujours avant le fetch/fetchAll
bien sûr.
Ça paraitrai logique, mais si ça se trouve PDO se débrouille pour que ça fonctionne quand même, qu'on le fasse avant ou après, je ne sais pas.
En tous cas dans le doute, essaie pour voir ?
public function prepare($statement, $attributes, $class_name, $one = false)
{
$req = $this->getPDO()->prepare($statement);
if ($class_name === null) {
$req->setFetchMode(PDO::FETCH_OBJ);
} else {
$req->setFetchMode(PDO::FETCH_CLASS, $class_name);
}
$req->execute($attributes);
if ($one) {
$datas = $req->fetch();
} else {
$datas = $req->fetchAll();
}
return $datas;
}
Ca ne marche pas non plus.
Sincèrement, merci pour vos idées et vos efforts déployés pour trouver une solution, et malheureusement, je crainds etre confronté à un bug vraiment ch*** à trouver
Dans "single.php" quand tu fais ça :
$post = $db->prepare('SELECT * FROM articles WHERE id = ?', [$_GET['id']], 'APP\Table\Article', true);
Le paramètre passé pour la "class" est : 'APP\Table\Article'
.
Ça me parait étrange de passer une classe de "table", ça ne devrait pas être une classe "d'entité" plutôt ?
Ca vient d'ici, à la 35eme minute :
https://www.grafikart.fr/formations/programmation-objet-php/tp-database
Et voici le code de la classe Article rangée dans App\Table :
Article.php
<?php
namespace APP\Table;
class Article{
public function __get($key){
$method = 'get' . ucfirst($key);
$this->$key = $this->$method();
return $this->$key;
}
public function getURL(){
return 'index.php?p=article&id=' . $this->id;
}
public function getExtrait(){
$html ='<p>' . substr($this->contenu, 0, 200) . ' ...</p>';
$html .= '<p><a href="' . $this->getURL() . '">Voir la suite</a></p>';
return $html;
}
}
Ah oui, zut.
Mets des echo
pour voir si ça correpsond bien à ce qu'on attend.
public function prepare($statement, $attributes, $class_name, $one = false)
{
$req = $this->getPDO()->prepare($statement);
if ($class_name === null) {
echo 'setFetchMode --- OBJ<br>';
$req->setFetchMode(PDO::FETCH_OBJ);
} else {
echo 'setFetchMode --- CLASS : ' . $class_name . '<br>';
$req->setFetchMode(PDO::FETCH_CLASS, $class_name);
}
$req->execute($attributes);
if ($one) {
$datas = $req->fetch();
} else {
$datas = $req->fetchAll();
}
return $datas;
}
Et est-ce qu'on peut voir l'intégralité du fichier App/Table/Article.php ?
Ton message s'est croisé avec mon edit ;-)
l'intégralité du fichier App/Table/Article.php est consultable sur mmon message édité
D'accord,
bon alors les echo
nous montrent bien qu'on obtient une "class", c'est ce qu'on voulait c'est bon.
Je me pose quand même la question :
Est-ce qu'on peut laisser "APP/...", ou on devrait respecter la casse ? Avec "App/..."
En tous cas,
En fait je ne comprend pas... Mais je laisse quand même ma "réflexion" ici, je ne sais pas, peut-être que ça pourra te faire penser à quelquechose qui t'aidera...
On obtient donc une class App/Table/Article
,
et cette classe n'a aucun attribut (seulement des méthodes).
Pourtant on essaie d'accéder à des attributs :
<h1><?= $post->titre; ?></h1>
Du coup la méthode magique est appelée.
public function __get($key) {
$method = 'get' . ucfirst($key);
$this->$key = $this->$method();
return $this->$key;
}
Dans cette méthode, on fait : $this->$key = ...
,
mais $this->$key
n'existe pas (la classe n'a aucun attribut). Absurde
Ça parait louche, mais finalement, ça ne me semble même pas pertinent de mentionner ça parce-que :
le message d'erreur ne dis pas : "on essaie d'accéder à un attribut qui n'existe pas",
il dit : "on essaie d'accéder à un attribut sur quelque chose qui n'est pas un objet".
Pourtant, on passe bien dans le $req->setFetchMode(PDO::FETCH_CLASS, $class_name);
,
et j'étais convaincu que ça nous donnerai un "objet" à la fin sur $datas
,
pourtant quand on fait un var_dump
sur ce qu'a retourné la fonction (la fonction "prepare"),
on a un "tableau"... :'(
Fais un var_dump()
juste avant le return, dans la fonction "prepare" pour voir ? (mais je commence à me dire qu'on s'éloigne de la solution...)
...
if ($one) {
$datas = $req->fetch();
} else {
$datas = $req->fetchAll();
}
var_dump($datas); // ici, on voit un "object" ou un "array" ???
return $datas;
}
oui, tu résumes parfaitement bien la problème qui semble absurde...
Pour le var_dump($data), placéà la fin de la méthode prepare(), ca retourne bien un array plutot qu'un objet :-(
Ah ben super ^^
Et du coup je me rend compte que je me suis bien embrouillé...
Quand on fait ça :
<h1><?= $post->titre; ?></h1>
On essaie pas d'accéder à l'attribut "titre" d'un objet instancié par la classe App/Table/Article, non.
On essaie d'accéder au champ "titre" sélectionné par la requête SQL.
Bref... ^^