2012-02-18 1 views
3

Désolé pour le mauvais anglais, je suis brésilien, et encore pire parler de la programmation. Allons-y. J'ai ceci:Singleton PDO Modèle - Hiérarchie

class DataBase extends PDO 
{ 

/** 
* @var object PDO 
*/ 
private static $instance; 


/** 
* Cria uma instância do PDO representando a conexão ao banco de dados e torna a instância disponível como "singleton" 
* 
* @param string $dsn   O DSN completo, ex.: mysql:host=localhost;dbname=testdb 
* @param string $username  O nome de usuário para a string DSN. Esse parâmetro é opcional para alguns drivers do PDO. 
* @param string $password  A senha para a string DSN. Esse parâmetro é opcional para alguns drivers do PDO. 
* @param array $driver_options Um array key => value de opções de conexão específicas do driver 
* 
* @return PDO 
*/ 
public 
function __construct() 
{ 

    global $config; 

    $dsn  = "mysql:dbname={$config['database'][AMBIENTE]['banco']};host={$config['database'][AMBIENTE]['url']}"; 
    $username = $config['database'][AMBIENTE]['usuario']; 
    $password = $config['database'][AMBIENTE]['senha']; 

    if (!isset (self::$instance)) 
    { 
     try 
     { 
      self::$instance = parent::__construct($dsn , $username , $password); 
     } 
     catch (PDOException $e) 
     { 
      Functions::Log('Erro de conexão de banco de dados: ' . $e->getMessage()); 
      header('HTTP/1.1 500 Internal Server Error'); 
     } 
    } 

    $this->storage = new ArrayObject(); 

} 

public static 
function getInstance() 
{ 
    if (!self::$instance) 
    { 
     self::$instance = new DataBase; 
    } 

    return self::$instance; 
} 

} 

et le modèle qui étend la DataBase classe:

class Model extends DataBase 
{ 
protected $TABLE_NAME; 
protected $TABLE_PREFIX; 
/* all logic here, like getters, setters and methods like update, delete and insert... */ 
} 

Mais je ne peux pas utiliser cette variable $ pour accéder aux méthodes PDO comme requête OU préparer. Il est dit que je ne suis pas appelé le constructeur PDO, même si le constructeur de ma classe Model appelle getInstance.

C'est possible?

+0

Pourquoi le constructeur de votre base de données est-il public? – busypeoples

+0

cocher self :: $ instance. C'est là que votre problème est. Si vous avez besoin d'un exemple de code, faites-le moi savoir. – busypeoples

+0

Pouvez-vous @busypeoples éclairer mes erreurs? Je pensais que toutes les méthodes magiques devraient être publiques par défaut. Je voudrais avoir un exemple! –

Répondre

2

Pour que votre exemple fonctionne, vous pouvez essayer ceci.

define('DB_CONN','mysql:dbname=;host='); 
define('DB_USER', ''); 
define('DB_PASS', ''); 

interface iMySQL 
{ 

    public 
    function query($string); 

    public 
    function select(); 

    public 
    function selectAll(); 

    public 
    function insert(); 

    public 
    function update(); 

    public 
    function delete(); 

    public 
    function load(); 

} 



class DataBase 
{ 

    /** 
    * @var object PDO 
    */ 
    private static $instance = null; 


    /** 
    * Cria uma instância do PDO representando a conexão ao banco de dados e torna a instância disponível como "singleton" 
    * 
    * @param string $dsn   O DSN completo, ex.: mysql:host=localhost;dbname=testdb 
    * @param string $username  O nome de usuário para a string DSN. Esse parâmetro é opcional para alguns drivers do PDO. 
    * @param string $password  A senha para a string DSN. Esse parâmetro é opcional para alguns drivers do PDO. 
    * @param array $driver_options Um array key => value de opções de conexão específicas do driver 
    * 
    */ 
    private function __construct() { 

    } 

    public static function getInstance() 
    { 
     if (self::$instance === null) 
     { 
      self::$instance = new PDO(DB_CONN, DB_USER, DB_PASS); 
     } 
     return self::$instance; 
    } 

} 

class Model 
{ 
    protected $TABLE_NAME; 
    protected $TABLE_PREFIX; 
    protected $clausula; 

    private $storage; 

    /** 
    * Recupera um registro utilizando sua chave 
    * 
    * @param string $key 
    * 
    * @return mixed O valor armazenado 
    * @throws RuntimeException Se não houver um registro para a chave especificada 
    */ 
    public 
    function __get($key) 
    { 

    } 

    /** 
    * Registra um valor à uma chave 
    * 
    * @param string $key A chave que será utilizada no registro 
    * @param mixed $value O valor que será registrado 
    * 
    * @throws LogicException Se a chave já estiver registrada 
    */ 
    public 
    function __set($key , $value) 
    { 
     //echo $key; 
    } 


    public static 
    function __callStatic($method , $args) 
    { 

     $database = DataBase::getInstance(); 
     $callback = array($database , $method); 
     return call_user_func_array($callback , $args); 

    } 

    public 
    function __call($method , $args) 
    { 

     $database = DataBase::getInstance(); 
     $callback = array($database , $method); 
     return call_user_func_array($callback , $args); 

    } 

    public function __construct($table_name = null , $id = null) 
    { 

     $this->TABLE_PREFIX = $this->config['database']['table_prefix']; 
     $this->TABLE_NAME = $this->TABLE_PREFIX . $table_name; 

     $this->storage = new ArrayObject(); 

     if (!is_null($table_name)) 
     { 
      $array = $this->query("SHOW COLUMNS FROM `$this->TABLE_NAME`")->fetchAll(); 

      $colunas  = array(); 
      $obrigatorias = array(); 

      foreach ($array as $value) 
      { 
       $colunas[] = $value[0]; 
       if ($value['Null'] === 'NO') 
       { 
        $obrigatorias[] = $value['Field']; 
       } 
      } 

      $this->colunas  = $colunas; 
      $this->obrigatorias = $obrigatorias; 
      $this->total_colunas = count($this->colunas); 

      // Se passou um id por parâmetro, salva nas propriedades do objeto 
      if (!is_null($id) AND is_numeric($id)) 
      { 
       $this->id = $id; 

       // E já carrega o objeto 
       $select = $this->query('SELECT * FROM {tabela_nome} WHERE `id` = ' . $id)->fetchObject(); 
       $this->load($select); 
      } 
     } 

    } 

    public 
    function insert() 
    { 
    } 

    public 
    function update() 
    { 
    } 

    public 
    function delete() 
    { 
    } 

    public 
    function select($clausula = NULL , $is_array = FALSE) 
    { 
     // Caso seja passado uma cláusula diretamente para a função, executa ela 
     if (!is_null($clausula)) 
     { 
      $this->clausula = $clausula; 
     } 

     // Troca uma possível variável pelo nome da tabela do Model 
     $this->clausula = (str_replace('{TABLE_NAME}' , $this->TABLE_NAME , $this->clausula)); 
     $this->clausula = (str_replace('{TABLE_PREFIX}' , $this->TABLE_PREFIX , $this->clausula)); 

     // Executa o SELECT no banco de dados 
     $query = $this->query($this->clausula); 

     if ($query AND $query->rowCount() > 0) 
     { 

      if ($query->rowCount() == 1 AND !$is_array) 
      { 
       return $query->fetchObject(get_class($this)); 
      } 
      else 
      { 
       $objetos = array(); 
       while ($linha = $query->fetchObject(get_class($this))) 
       { 
        $objetos[] = $linha; 
       } 
       return (count($objetos) > 0) ? $objetos : FALSE; 
      } 
     } 
     else 
     { 
      return FALSE; 
     } 
    } 

    public 
    function selectAll() 
    { 
    } 

    public 
    function load() 
    { 
    } 
} 



$model = new Model(); 
$stmt = $model->query(); 
$fetch = $stmt->fetchAll(); 
var_dump($fetch); 

Ceci n'a pas été testé. Mais cela devrait vous donner une idée de la façon de résoudre le problème. Essayez cette approche.

define('DB_TYPE', 'DB_Class_One'); 


class DB_Class_One extends PDO { 
    public function getData() { 
     print 'Class One'; 
    } 
} 

class DB_Class_Two extends PDO { 
    public function getData() { 
     print 'Class Two'; 
    } 
} 

class DB_Class_Three extends PDO { 
    public function getData() { 
     print 'Class Three'; 
    } 
} 

class DataBase { 

    private static $instance = null; 

    private function __construct() { 

    } 

    private function __clone() { 

    } 

    public static function getInstance() { 
     $class = DB_TYPE; 

     if (self::$instance === null) { 
      self::$instance = new $class("mysql:host=;dbname=", '', ''); 
     } 
     return self::$instance; 
    } 


} 




$db = DataBase::getInstance(); 

$stmt = $db->query(); 

$result = $stmt->fetch(); 

$db->getData(); 
+0

En fonction de mes essais, j'obtiens "Aucune construction PDO n'a été appelée" ou "call_user_func_array() attend le paramètre 1 est un rappel valide, la classe 'DataBase' n'a pas de méthode 'query' "TOUJOURS. Le code complet est affiché ici: http://pastebin.com/BwPvh3mV ​​ –

+0

Ne pas étendre la classe de noyau. Essayez de rendre les classes aussi indépendantes que possible. Créez un registre et ajoutez toutes les variables de base. Ou créez un fichier de configuration et utilisez define() pour définir toutes les données de configuration. Avez-vous essayé l'approche ci-dessus. Je l'ai testé maintenant, ça va marcher. – busypeoples

+0

désolé de vous troubler @busypeoples. Je ne peux toujours pas utiliser la méthode $ this-> sur mon modèle, en l'étendant ou non à la classe DataBase. Pouvez-vous écrire un cours correct pour moi? Je peux effectuer un paiement via PayPal pour vous. –

0

Quelque chose semble drôle au sujet de votre méthode getInstance()et votre constructeur à la fois à l'attribution self::$instance:

function getInstance() 
{ 
    if (!self::$instance) 
    { 
     self::$instance = new DataBase; 
    } 

/* .... */ 

function __construct() 
{ 

/* .... */ 

    if (!isset (self::$instance)) 
    { 
     try 
     { 
      self::$instance = parent::__construct($dsn , $username , $password); 
     } 

supprimer l'affectation de getInstance() et voir si cela fonctionne.

+0

C'est un wrapper singleton AOP. Je pensais pouvoir utiliser un modèle juste en étendant cette classe DataBase, mais cela ne fonctionne pas. La meilleure approche à ce moment est d'utiliser __call pour transférer les appels à la propriété $ instance qui est où une instance PDO est stockée. Mais $ this-> query() ne fonctionne pas. –

+0

Il existe un moyen de truquer les IDE pour coder l'achèvement de ma classe de modèle en pensant qu'il s'agit d'un PDO? Je voudrais utiliser à l'intérieur de la classe Modèle $ this-> que (requête popup) –

+0

Désolé, je n'ai pas pris la peine de mettre en place des bits d'auto-complétion dans 'vim', mon éditeur de choix. – sarnold