Le moyen le plus propre d'utiliser la base de donnée

Le problème exposé dans ce sujet a été résolu.

Bonjour, j'ai commencé il y a pas très longtemps la création d'un site web, c'est mon premier site en POO, mon problème est pour l’accès a la base de donnée, je ne sais pas comment faire cela proprement. J'ai créer un objet que je créer au début de chaque page.

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
<?php
class Database{
    private $connection;

    public function __construct($config) {
        $this->openConnection($config);
    }

    public function openConnection($config) {
        try {
            $this->connection = new PDO('mysql:host=' . $config['database']['host'] . '; dbname=' . $config['database']['database'], $config['database']['user'], $config['database']['password']);
            $this->connection->setAttribute(PDO::ATTR_ERRMODE, PDO::ERRMODE_EXCEPTION);
        } catch (PDOException $e) {
            echo 'There was an error connecting to the database, Error: ' . $e->getMessage();
            die();
        }
    }

    public function getAll($sql, array $params) {
        $stmt = $this->connection->prepare($sql);
        $stmt->execute($params);
        return $stmt->fetch(PDO::FETCH_ASSOC);
    }
}

dans mon index.php il y a donc

1
2
3
<?php
include ('classes/Database.class.php');
$Database = new Database($config);

et lorsque je veu l'utiliser dans un objet c'est là que je ne sais pas quoi choisir : utiliser 'global' ou importer $Database à chaque fois que j’appelle une fonction requièrent un accès Mysql.

Voilà donc si quelqu'un pouvait me dire qu'elle est la meilleur méthode à utiliser je lui en serait vraiment reconnaissant.

Bonne soirée !

et lorsque je veu l'utiliser dans un objet c'est là que je ne sais pas quoi choisir : utiliser 'global' ou importer $Database à chaque fois que j’appelle une fonction requièrent un accès Mysql.

en fait une méthode "simple" est d'instancier une fois ta connexion puis de la passer en argument des méthodes qui en ont besoin.

Ah ok, donc si je comprend bien c'est ce que je voulais dire par "importer $Database". Juste pour être sure que je t'ai bien compris, c'est bien un truc du genre :

1
2
3
4
5
6
7
<?php
class Test{

     public function test($db){
          //function qui utilise $db
     }
}

Si c'est ça tant mieux c'est ce que j'ai commencer a faire. Merci d'avoir pris le temps de me répondre

J'ai aussi utiliser une autre solution (Je ne sais pas si elle est bien), mais j'ai une classe Manager qui ressemble à ça:

 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
<?php
abstract class Manager{
    /**
     * @var $_db PDO
     */
    private static $_db;

    public static function db(){
        if(Manager::$_db == null){
            try{
                Manager::$_db = new PDO('mysql:host=localhost;dbname=etude', 'root', '');
                Manager::$_db->exec("SET CHARACTER SET utf8");
            }catch(Exception $e){
                die('Erreur : '.$e->getMessage());
            }
        }

        if(Manager::$_db == null){
            echo 'Error initialize Database';
            exit();
        }

        return Manager::$_db;
    }
}

Et quand j'ai besoin de faire une requête je fais comme ceci:

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
<?php
public class HomeWork extends Manager{ //....

public static function add(HomeWork $hw){
    $req = Manager::db()->prepare("
        INSERT INTO homeworks
        (user, branch, hwDate, writtenWork, detail)
        VALUES
        (:user, :branch, :hwDate, :writtenWork, :detail)
    ");
       //....
}

(Ma classe Manager correspondant à ta classe DataBase)

+1 -0

La principale raison de ne pas utiliser de globales : n'importe quel code peut les modifier, donc, si tu as un problème, tu ne sauras pas d'où il vient. C'est pour cela que l'on essaye de tout modulariser, tout compartimenter : si il y a un problème avec x, on a qu'un seul endroit où regarder pour trouver le problème.

Ok, merci donc je laisse tomber les globales. Sinon, ce que je voulais faire à la base c'est simplifier PDO pour que ce soit plus lisible.

Je me suis basé sur ce que j'ai trouvé sur internet et j'ai ajouter et modifier comme j'en avais besoin ce qui donne cet objet :

 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
<?php
class Database{

    private $connection;

    public function __construct($config) {
        $this->openConnection($config);
    }

    public function openConnection($config) {
        try {
            $this->connection = new PDO('mysql:host=' . $config['database']['host'] . '; dbname=' . $config['database']['database'], $config['database']['user'], $config['database']['password']);
            $this->connection->setAttribute(PDO::ATTR_ERRMODE, PDO::ERRMODE_EXCEPTION);
        } catch (PDOException $e) {
            echo 'There was an error connecting to the database, Error: ' . $e->getMessage();
            die();
        }
    }

    public function getAll($sql, array $params) {

        $stmt = $this->connection->prepare($sql);
        $stmt->execute($params);
        return $stmt->fetch(PDO::FETCH_ASSOC);

        $stmt->closeCursor();
    }

    public function execute($sql, array $params) {
        $stmt = $this->connection->prepare($sql);
        $stmt->execute($params);
        $stmt->closeCursor();
    }

    public function isEntryExist($sql, array $params) {
        $result = $this->getAll($sql, $params);
        if($data = $result->fetch()){
            return true;
        }
        else{
            return false;
        }
    }
}

je met ça au début de ma page :

1
2
<?php
$db = new Database($config);

et quand j'ai besoin je le met en argument, c'est très pratique, au début de mes pages je créer l'objet et quand j'ai besoin de vérifier si une entrée existe par exemple je n'ai besoin que d'une ligne. Mon soucis c'est pour getAll(), habituellement je fais ceci :

1
2
3
4
5
6
<?php
$req = $bdd->query('SELECT * FROM users');
while ($req = $data->fetch())
{
echo $data['pseudo'];
}

mais comment continuer a faire ça avec mon objet Database ?

Merci d'avoir pris le temps de répondre

Juste pour préciser, la méthode de WinXaito s'appelle le factory pattern.

Euh non, c'est un singleton. Le but est de n'avoir qu'une seule instance (a single instance) de la connexion à la db.

+1 -0

Ce n'est pas un singleton au sens strict. La classe ne se restraint pas elle même à une seul instance, il y a un manager.

Il n'y a pas de restriction sur ce que retourne une factory, qu'il retourne toujours la même instance ou une instance différente à chaque fois, ça reste une factory.

C'est une factory dans le sens où un object Foo gère l'instanciation d'un objet Bar. C'est un singleton dans le sens où on appelle une méthode qui nous retourne toujours la même instance. C'est un mélange, j'aurai dû être plus précis.

Le problème des singletons classiques est que l'objet gère plusieurs choses (contraire à SOLID). Pour résoudre le problème, j'aurai quand même tendance à utiliser un dependency container simpliste :

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
<?php

$c = new \Container;

$c->set('config', function () {
    return get_config();
});

$c->set('database', function () {
    return get_database($this->get('config'));
});

$c->get('database');
$c->get('database'); // retourne la même instance, n'exécute pas les closures plus d'une fois

D'accord, je vais utiliser la solution que j'ai proposé mais avec cette solution je ne sais pas comment récupérer les données d'un SELECT par exemple, je sais les afficher avec 'var_dump' mais comment faire ce que je faisait avant avec :

1
2
3
4
5
6
<?php
$req = $bdd->query('SELECT * FROM users');
while ($req = $data->fetch())
{
echo $data['pseudo'];
}

?

Je vous remercie de nouveaux pour votre aide, heureusement que vous êtes là pour m'aider et que vous en avez la patience.

Salut,

L'idée est de complètement séparer tes appels à la BDD et ton exploitation des résultats de ta requête. En l'occurrence, j'adapterais ta méthode getAll en me servant de la méthode PDO fetchAll(), qui retourne tous les résultats de la requête d'un coup, comme ceci :

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
<?php
/**
 * @param string $sql
 * @param array $params
 * @return array $results
 */
public function getAll($sql, array $params)
{
        $stmt = $this->connection->prepare($sql);
        $stmt->execute($params);
        $results = $stmt->fetchAll(PDO::FETCH_ASSOC);
        // Un code écrit après un return n'est pas exécuté, il faut donc d'abord fermer le curseur avant de return
        $stmt->closeCursor();

        return $results;
}

Quand tu appelles getAll depuis ton code, tu es libre de faire tout ce que tu veux avec l'array de résultats.

Remarque : ta méthode execute ne retourne rien, je ne suis pas sûr que ce soit le comportement voulu. D'ailleurs, attention, avec les changements que je te donne, il faut également modifier ta méthode isEntryExist, puisqu'elle recevra un array.

Petite remarque : un if(condition) {return true;} else {return false;} peut avantageusement se contracter en return condition. :)
A titre perso, je ne suis pas trop fan de la convention de nommage isEntryExist, je connais le principe de rajouter un "is" devant les méthodes qui retournent un booléen, mais en l'occurrence ça ne veut plus dire grand-chose. Que dirais-tu de isInDatabase ou isRegistered ? Ou encore entryExists si l'on laisse tomber le "is".

Edit: typo

+1 -0

Ok, dejà, merci d'avoir pris le temps de répondre avec un message aussi complet ! :) Ducoup execute il ne retourne rien et c'est voulu je m'en sert pour les INSERT par exemple.

Pour le return condition merci beaucoup, je ne connaissais pas et c'est très pratique. J'ai renommer ma fonction isEntryExist en isInDatabase, je savais bien que quelque chose allait pas avec ce nom mais je ne savais pas quoi mettre d'autre donc merci :)

et sinon pour ce qui est de getAll, j'ai mis ce que tu m'a proposé, tu as bien fait de me dire que après le return rien n'était exécuté j'aurais pu chercher très longtemps des problèmes sinon :)

Bref en prenant en compte ce que tu m'a dis j'ai obtenu ceci :

 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
<?php
class Database{

    private $connection;

    public function __construct($config) {
        $this->openConnection($config);
    }

    public function openConnection($config) {
        try {
            $this->connection = new PDO('mysql:host=' . $config['database']['host'] . '; dbname=' . $config['database']['database'], $config['database']['user'], $config['database']['password']);
            $this->connection->setAttribute(PDO::ATTR_ERRMODE, PDO::ERRMODE_EXCEPTION);
        } catch (PDOException $e) {
            echo 'There was an error connecting to the database, Error: ' . $e->getMessage();
            die();
        }
    }

    public function getAll($sql, array $params)
    {
        $stmt = $this->connection->prepare($sql);
        $stmt->execute($params);
        $results = $stmt->fetchAll(PDO::FETCH_ASSOC);

        $stmt->closeCursor();

        return $results;
    }

    public function execute($sql, array $params) {
        $stmt = $this->connection->prepare($sql);
        $stmt->execute($params);
        $stmt->closeCursor();
    }

    public function isInDatabase($sql, array $params) {
        $result = $this->getAll($sql, $params);
        return !empty($result);
    }
}

Voici mon petit script pour tester :

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
<?php 
/* test de getAll */

$data = $db->getAll('SELECT * FROM users', array(''));

foreach($data as $test){
    echo $test['pseudo']; 
    echo $test['id'];
    echo '<br/>';
}

/*test de execute */

$db->execute('INSERT INTO users(pseudo, mail) VALUES(:pseudo, :mail)', array('pseudo' =>'celiandu61', 'mail' =>'celianvdb@hotmail.fr')); 

/*test de isInDatabase + verif de execute */

echo '<br/>';
echo $db->isInDatabase('SELECT * FROM users WHERE mail = ?', array('celianvdb@hotmail.fr'));

?>

et le résultat :

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
Pseudo :celiandu61 Id :43
Pseudo :celiandu61 Id :44
Pseudo :celiandu61 Id :45
Pseudo :celiandu61 Id :46
Pseudo :celiandu61 Id :47
Pseudo :celiandu61 Id :48
Pseudo :celiandu61 Id :49
Pseudo :celiandu61 Id :50
Pseudo :celiandu61 Id :51
Pseudo :celiandu61 Id :52
Pseudo :celiandu61 Id :53
Pseudo :celiandu61 Id :54
Pseudo :celiandu61 Id :55
Pseudo :celiandu61 Id :56
Pseudo :celiandu61 Id :57
Pseudo :celiandu61 Id :58

1

C'est parfait, je te remercie énormément pour ton aide qui me permet de continuer mon projet ! Merci également aux autres qui m'ont permis d'apprendre pas mal de choses ! Je passe le sujet en clos. Bonne soirée et encore merci !

Connectez-vous pour pouvoir poster un message.
Connexion

Pas encore membre ?

Créez un compte en une minute pour profiter pleinement de toutes les fonctionnalités de Zeste de Savoir. Ici, tout est gratuit et sans publicité.
Créer un compte