Pagina 1 di 2 1 2 ultimoultimo
Visualizzazione dei risultati da 1 a 10 su 19
  1. #1
    Utente di HTML.it L'avatar di Fractals87
    Registrato dal
    Apr 2008
    Messaggi
    1,202

    [PDO] Extend Pdo uncatch error connection

    Scusate ma mi sto proprio innervosendo.
    Allora ho esteso la classe pdo riscrivendo il metodo construct.
    Questa struttra non permette di sollevare l'eccezzione nel caso ci fosse un errore nella connessione al db.

    Mi sono detto bene, che pirla che sono, se gli setto l'attributo dopo aver invocato il costruttore è normale che non avvenga il catch.

    ho provato a mettere l'array in questo modo :
    parent::__construct($dns, $settings['database']['username'], $settings['database']['password'],array(PDO::ATTR_ERRMODE => PDO::ERRMODE_WARNING))
    ma questo non setta correttamente err_mod
    Se io faccio un get attribute dopo aver creato l'oggetto mypdo (facendo in modo che la connessione vada a buon fine) il mio err_mode è 0 (cosa che dovrebbe essere due)


    Codice PHP:
    <?php
    class MyPDO extends PDO {
        
        public function 
    __construct ($file 'config/my_setting.ini') { 
            try{
                    if (!
    $settings parse_ini_file($fileTRUE)) throw new exception('Unable to open ' $file '.');
            
                 
    $dns $settings['database']['driver'] .
                    
    ':host=' $settings['database']['host'] .
                    ((!empty(
    $settings['database']['port'])) ? (';port=' $settings['database']['port']) : '') .
                    
    ';dbname=' $settings['database']['schema'];
            
                    
    parent::__construct($dns$settings['database']['username'], $settings['database']['password']);
                    
    self::setAttribute(PDO::ATTR_ERRMODEPDO::ERRMODE_EXCEPTION);
                    
            }catch(
    PDOException $e){
                
    //COMPORTAMENTO COMUNE PER 
                
    echo 'Connection failed: ' $e->getMessage();
                 exit();
            }
        }

    ?>
    Che mestiere difficile.....essere da soli ancora di più

  2. #2
    Utente di HTML.it L'avatar di .Kurt
    Registrato dal
    Jul 2007
    Messaggi
    654
    Probabilmente vorresti modificare
    Codice PHP:
    self::setAttribute(PDO::ATTR_ERRMODEPDO::ERRMODE_EXCEPTION); 
    in
    Codice PHP:
    $this->setAttribute(PDO::ATTR_ERRMODEPDO::ERRMODE_EXCEPTION); 

  3. #3
    Utente di HTML.it L'avatar di Fractals87
    Registrato dal
    Apr 2008
    Messaggi
    1,202
    ho provato ma ottengo lo stesso risultato.
    Se io setto l'attributo con self o this, l'err_mode viene settato correttamente ma non genera eccezzione nella connessione, ma solo per i successivi errori
    Che mestiere difficile.....essere da soli ancora di più

  4. #4
    - l'apertura della connessione deve avvenire con chiamata a metodo pubblico opportuno, non nel costruttore

    - la classe non deve parsarsi da sola il file di configurazione, ma deve avere getter e setter opportuni per essere configurata da una classe esterna

    - più che estendere Pdo, la tua classe dovrebbe usare Pdo per fornire un livello di astrazione più elevato/comodo, altrimenti fai prima ad usare direttamente Pdo
    IP-PBX management: http://www.easypbx.it

    Old account: 2126 messages
    Oldest account: 3559 messages

  5. #5
    Utente di HTML.it L'avatar di Fractals87
    Registrato dal
    Apr 2008
    Messaggi
    1,202
    1. Perchè consigli questo approccio?

    2. Per il file di configurazione l'avevo pensata in questo modo :
    Nel costruttore ho il mio valore di default : $file = 'config/my_setting.ini'
    invocando l'oggetto in questo modo
    $db = New MyPDO();
    In un probabile futuro, dove debba connettermi a due database contemporaneamente
    bastava passare un altro file di configurazione es :
    $db = New MyPDO('file2config.ini');

    Dato che il file .ini ha questa struttura
    [database]
    driver = mysql
    host = localhost
    ;port = 3306
    schema = miodb
    username = user
    password = pwd

    Avevo pensato di passare il riferimento dell'array ed aggiungere i nuovi parametri

    [database]
    driver = mysql
    host = localhost
    ;port = 3306
    schema = miodb
    username = user
    password = pwd

    [database2]
    driver = mysql
    host = localhost
    ;port = 3306
    schema = miodb
    username = user
    password = pwd

    e chiamare l'oggetto in questo modo
    $db = New MyPDO('database')
    $db = New MyPDO('database2')

    Andando poi a prelevare le info corrette

    3. Avevo valutato di estendere pdo per due motivi :
    utilizzando una classe indipendente avrei dovuto riscrivere tutti i metodi per averli dispobili e in secondo luogo pensavo in un fututo di aggiungere metodi utili mancanti nella classe pdo Es il count dei record estratti

    Sono considerazioni e valutazioni fatte da una persona ignorante in oop percui perdonami se ti sembrano senza senso
    Che mestiere difficile.....essere da soli ancora di più

  6. #6
    1 - Vabbeh su questo punto posso anche passare, anche perchè in php ha poco senso

    2 - Te la butto li: e se domani il file di configurazione è un xml? e poi Yaml? e poi un array php? e poi un config in altro formato, che fai? Crei una driver per ogni formato di configurazione? per questo non è responsabilità del driver parsarsi il file di configurazione, ma deve essere configurato il driver da chi lo usa

    3 - cos'è PDO?

    The PHP Data Objects (PDO) extension defines a lightweight, consistent interface for accessing databases in PHP
    "PDO definisce un'interfaccia leggera e consistente per accedere al database", ed è tutto quello che deve fare, non c'ha proprio altro da aggiungere. Sopra questa interfaccia puoi aggiungere uno strato maggiore di astrazione che PDO come "metodo secco" magari non include.

    Detta poi sinceramente, l'idea di "reinventare la ruota" lascia il tempo che trova, a meno che tu non lo stia facendo per studio. Per il primo punto, ti suggerisco di usare una libreria già pronta e testata e funzionante, come Doctrine2/DBAL o direttamente l'ORM di Doctrine2. Per il secondo punto, ti suggerisco di guardare a quello che fa DBAL, magari proprio a livello di codice sorgente https://github.com/doctrine/dbal/tre.../Doctrine/DBAL

    se cerchi poi materiale su internet, dovresti trovare molto sulla falsa riga di PDO vs DBAL o simili, ma un esempio di cosa voglia dire "aggiungere funzionalità a pdo" potrebbe essere l'ultima parte di questo articolo, http://gonzalo123.com/2011/07/11/dat...o-versus-dbal/ ... e DBAL\Connection non estende PDO

    Quello che vuoi fare te è pari pari questa classe https://github.com/doctrine/dbal/blo...Connection.php
    IP-PBX management: http://www.easypbx.it

    Old account: 2126 messages
    Oldest account: 3559 messages

  7. #7
    Se poi vogliamo cominciare ad astrarci dall'uso diretto del database (quindi alzare il livello rispetto a PDO/DBAL) si passa proprio ad altri pattern, ad esempio:

    Data Source Architectural Patterns: Table Data Gateway (144), Row Data Gateway (152), Active Record (160), Data Mapper (165).

    Object-Relational Behavioral Patterns: Unit of Work (184), Identity Map (195), Lazy Load (200)

    Object-Relational Structural Patterns: Identity Field (216), Foreign Key Mapping (236), Association Table Mapping (248), Dependent Mapping (262), Embedded Value (268), Serialized LOB (272), Single Table Inheritance (278), Class Table Inheritance (285), Concrete Table Inheritance (293), Inheritance Mappers (302).

    Object-Relational Metadata Mapping Patterns: Metadata Mapping (306), Query Object (316), Repository (322).
    link: http://www.martinfowler.com/eaaCatalog/index.html (di cui ti suggerisco caldamente il libro, spettacolare)
    IP-PBX management: http://www.easypbx.it

    Old account: 2126 messages
    Oldest account: 3559 messages

  8. #8
    Utente di HTML.it L'avatar di Fractals87
    Registrato dal
    Apr 2008
    Messaggi
    1,202
    Ciao Santino83,

    Premetto che ho moltissima considerazione di te e ti ringrazio per lo sforzo che ogni santa volta fai per le mie assurde domande.
    Volevo illustrarti un la mia situazione e le considerazioni fatte in seguito alla lettura delle tue risposte.
    Attualmente sto utilizzando la versione 5.1.6 di php (molto molto vecchia).
    La mia applicazione ha web diverse decine di pagine web.
    Nessuna applicazione di pattern, o standard oop.
    Forma totalmente procedurale (a volte molto disorganizzata).

    Ovviamente a questo punto sta iniziando ad essere difficile manutenere tutto.
    Un programmatore con i @@ ovviamente rifarebbe tutto da 0 o quasi.
    Questo ovviamente non me lo posso permettere per ovvi motivi.

    Ho guardato approfonditamente doctrine e con tutta franchezza ci ho capito veramente veramente poco.
    E' vero le classi, le interfacce ecc le ho studiate sulla carta (Animale -> Mamminefero -> Cavallo : Nitrisce.... soliti esempi inutili).
    Ma non avendo una conoscenza approfondita ovviamente è impossibile capire a fondo le potenzialità di doctrine peggio ancora se andiamo a astrarre totalmente l'applicazione dalla base dati.
    Già il fatto di utilizzare una vecchia versione di php mi limita dal fatto di non poterlo implementare a fondo, e detto con tt franchezza non vorrei implementare una cosa che non capisco.

    Preferirei iniziare con un piccolo passo ovvero l'introduzione di una classe database per l'utilizzo di pdo (abbandonando definitivamente mysql_connection) soprattutto perchè mi sono reso conto di avere necessità delle transazioni.
    (puoi solo immaginare i problemi di insert o update che posso avere senza nessun controllo e gestione di errori)
    La costruzione di una classe per una gestione corretta dei dati in input dell'utente.
    Il prossimo sviluppo di due macro oggetti che concettualmente sono presenti nella mia applicazione per semplificarmi la vita :
    Utenti
    Interventi : Quest'ultimo possibilmente sviluppandolo socondo il pattern mvc

    So che sembra un pastrocchio nel senso che nello sviluppo avro connessione mysql, connessione pdo, classi, forma procedurale, e una classe aderente al pattern mvc.
    Ma mi è impossibile andare ad implementare e manutenere contemporanemento.

    Dato questa seeemplice premessa pensavo di iniziare in questo modo :

    Codice PHP:
    class MyPDO extends PDO {
        
        public function 
    __construct ($file 'config/my_setting.ini') { 

            if (!
    $settings parse_ini_file($fileTRUE)) throw new PDOException('Unable to open ' $file '.');
            
             
    $dns $settings['database']['driver'] .
              
    ':host=' $settings['database']['host'] .
              ((!empty(
    $settings['database']['port'])) ? (';port=' $settings['database']['port']) : '') .
              
    ';dbname=' $settings['database']['schema'];
              
              
    parent::__construct($dns$settings['database']['username'], $settings['database']['password']);
              
    self::setAttribute(PDO::ATTR_ERRMODEPDO::ERRMODE_EXCEPTION);            
        }

    Classe di partenza pdo.
    Mi piacerebbe integrarla per avere un singolo punto di accesso per il recupero dei parametri e per il settaggio dei della modalità di errore.
    Ho mantenuto estensione della classe pdo dato che ho trovato la stessa forma nel listato di doctrine.
    Sotto il tuo consiglio ho esternalizzato la gestione dell'errore (come farò poi in tutte le classi) fino a che non padroneggero il pattern observer (ottimo consiglio).
    Ti invito a suggerirmi un processo migliore per il settaggio dei parametri per la connessione che ritine più corretto.

    Nelle mie pagine avrò percui la seguente struttura :

    Codice PHP:
    /*-------------INCLUDE CLASS---------------*/
    include "class/mypdo.class.php";
    /*-------------INCLUDE CLASS---------------*/
    try{
        
    $db = new MyPDO();
    }catch(
    PDOException $e){
        
    //Gestione dell'errore di connessione
         
    exit();
    }


    try{
        
    $sql $db->prepare('SELECT user FROM utent');
        
    $sql->execute(); 
        foreach(
    $sql->fetchAll() as $rk){  
            echo 
    $rk['user']. '
    '
    ;    
        }
    }catch (
    PDOException $e) {
        
    //Gestione dell'errore

    Per le altre classi (Controllo parametri in input, utenti, interventi) effettuerò altre Wall of Text mettendo alla prova la vostra grande pazienza...

    Già queste cose porterebbero un miglioramente inimmaginabile alla mia applicazione.

    Ti autorizzo a mandarmi a quel paese nel caso il mio approccio sia totalmente errato e a suggerirmi un approccio semplicistico per poter iniziare a fare le cose con più ordine.
    Che mestiere difficile.....essere da soli ancora di più

  9. #9
    Tanto per fare un esempio, con tutti gli errori e i difetti del caso, oltre all'incompletezza della soluzione:


    1) il parsing dei file di configurazione nonchè la loro gestione non può essere propria della classe che usa il db, quindi sposti tutto in un'altra classe che chiameremo per semplicità Configuration:

    Codice PHP:

    <?php

    //Configuration.php

    class Configuration{
        
        const 
    PATH_DELIMITER '.';
        
        private 
    $configuration = array();
        private 
    $resource;
        
        public function 
    __construct($resource){
            
            
    $this->resource $resource;
            
    $this->_parse();
        }
        
        private function 
    _parse(){
            
            if(
    is_readable($this->resource)===false)
                throw new 
    Exception("Impossibile aprire il file di configurazione ".$this->resource);
            
            
    $this->configuration parse_ini_file($this->resource,true);
        }
        
         public function 
    get($path$default null){
            
            
    $r $this->search($path);
            if(
    $r['_found']===true)
            {
                return 
    $r['_value'];
            }
            
            return 
    $default;
        }
        
        public function 
    set($path,$value){
            
            
    $r $this->search($path,true);
            
    $r['_value'] = $value;
            
            return 
    $this;
        }
        
        private function 
    search($path,$create false){
            
            
    $rit = array('_found' => false'_value' => null);
            
            
    $keys explode(self::PATH_DELIMITER,$path);
            
            if(!
    is_array($this->configuration))
            {
                if(
    $this->configuration!==null)
                    
    $this->configuration = array($this->configuration);
                else
                    
    $this->configuration = array();
            }
            
            
    $tmp =& $this->configuration;
            
            
    $lastKeyI count($keys)-1;
            
            foreach(
    $keys as $i => $key)
            {
                if(!
    is_array($tmp) || !array_key_exists($key$tmp))
                {
                    if(!
    $create)
                        break;
                    
                    
    $tmp[$key] = array();
                    
    $tmp =& $tmp[$key];
                    
                }else if(
    array_key_exists($key$tmp)){
                    
                    if(
    $i == $lastKeyI)
                    {
                        
    $rit['_found'] = true;
                    }
                    
                    
    $tmp =& $tmp[$key];
                }
                
                
    $rit['_value'] =& $tmp;
            }
            
            if(
    $rit['_found']===false && $create === false)
                
    $rit['_value'] = null;
            
            return 
    $rit;
        }
    }

    /*
    esempio di utilizzo:

    database.ini:

    [database]
    database = miodatabase
    host = localhost
    driver = pgsql
    username = postgres
    password = 

    $configuration = new Configuration('/path/to/database.ini');

    print_r($configuration->get('database'));

    echo $configuration->get('database.username');

    $configuration->set('foo.bar',"foobar");

    echo $configuration->get('foo.bar');

    */
    2) Ispirandoci a questa classe: https://github.com/doctrine/dbal/blo...Connection.php proviamo a fare noi un esempio:

    Codice PHP:
    <?php

    //DB.php

    class DB{
        
        
    /**
         *
         * @var PDO
         */
        
    private $pdo;
        
        private 
    $database;
        private 
    $driver;
        private 
    $username;
        private 
    $password;
        private 
    $host;
        private 
    $port;
        
        private 
    $connected;
        public 
    $lastError;
        
        public function 
    __construct($database='',$driver='',$username='',$password='',$host='',$port=0) {
            
    $this->database $database;
            
    $this->driver $driver;
            
    $this->username $username;
            
    $this->password $password;
            
    $this->host $host;
            
    $this->port $port;
            
    $this->connected false;
        }
        
        public function 
    getDatabase(){
            return 
    $this->database;
        }
        
        public function 
    setDatabase($database){
            
    $this->database $database;
            return 
    $this;
        }
        
        
    //altri getter/setter per driver/username/password/host/port
        
        
    public function connect(){
            
            if(
    $this->isConnected())
                throw new 
    Exception('Connessione già attiva');
            
            try{
                
                
    $dsn $this->getDSN();
                
    $this->pdo = new PDO($dsn$this->username$this->password, array(PDO::ATTR_ERRMODE => PDO::ERRMODE_EXCEPTION));
                
    $this->connected true;
                
            }catch(
    PDOException $ex){
                
    $this->pdo null;
                
    $this->connected false;
                
    //intercetto tutte le mie eccezioni e le gestisco come ritengo più opportuno
                //ma eviterei di propagare PDOExceptions fuori da questa classe
                //perchè è suo compito gestirle, al limite rilanciando eccezioni di 
                //diverso tipo relative alla tua applicazione definite con altre classi 
                
    $this->lastError $ex->getMessage();
            }
            
            return 
    $this->isConnected();
        }
        
        public function 
    isConnected(){
            return 
    $this->connected && $this->pdo !== null;
        }
        
        private function 
    getDSN(){
            
            return 
    $this->driver 
                    
    ':host=' $this->host 
                    ( 
    $this->port ';port=' $this->port '') . 
                    
    ';dbname=' $this->database
        }
        
        
    //ci metto tutte le funzioni esposte da PDO che mi pare, usandole in maniera più friendly, es:
        
        
    public function fetchAll($sql, array $params = array())
        {
            return 
    $this->executeQuery($sql$params)->fetchAll();
        }
        
        public function 
    delete($tableName,array $params = array()){
            
            
    $criteria = array();
                    
            foreach(
    array_keys($params) as $columnName)
            {
                
    $criteria[] = $columnName.' = ?';
            }
            
            
    $sql 'DELETE FROM '.$tableName.' WHERE '.implode(' AND ',$criteria);
            
            return 
    $this->executeUpdate($sqlarray_values($params));
        }
        
        public function 
    executeQuery($sql,array $params = array()){
            
            
    //PDOStatement
            
    $smt null;
            
            if(
    $params)
            {
                
    $smt $this->pdo->prepare($sql);
                foreach(
    $params as $key => $value)
                {
                    if(
    is_numeric($key))
                        
    $smt->bindValue($key+1$value);
                    else
                        
    $smt->bindValue (":$key"$value);
                }
                
                
    $smt->execute();
            }else{
                
    $smt $this->pdo->query($sql);
            }
            
            return 
    $smt;
        }
        
        public function 
    executeUpdate($sql, array $params = array()){
            
            
    $result 0;
            
            if(
    $params)
            {
                
    $smt $this->pdo->prepare($sql);
                foreach(
    $params as $key => $value)
                {
                    if(
    is_numeric($key))
                        
    $smt->bindValue($key+1$value);
                    else
                        
    $smt->bindValue (":$key"$value);
                }
                
                
    $smt->execute();
                
    $result $smt->rowCount();
            }else{
                
    $result $this->pdo->exec($sql);
            }
            
            return 
    $result;
        }
        
        public function 
    beginTransaction(){
            
    //..
        
    }
        
        public function 
    commit(){
            
    //..
        
    }
    }
    3) Mettiamo tutto insieme:

    Codice PHP:

    include_once "Configuration.php";
    include_once 
    "DB.php";

    $configuration = new Configuration(__DIR__.DIRECTORY_SEPARATOR.'database.ini');

    $db = new DB($configuration->get('database.database'),
                 
    $configuration->get('database.driver'),
                 
    $configuration->get('database.username'),
                 
    $configuration->get('database.password'),
                 
    $configuration->get('database.host'));

    if(!
    $db->connect())
        die(
    $db->lastError);


    foreach(
    $db->fetchAll("select * from users") as $row){
        
    print_r($row);
    }


    foreach(
    $db->fetchAll("select * from users where id = ?",array('114')) as $row){
        
    print_r($row);
    }

    echo 
    "deleted: ".$db->delete('users',array('id'=>127)); 
    Ovviamente, se tu nel tuo progetto ti includi la libreria di Doctrine e usi soltanto o inizia partendo dall'usare la loro Classe Connection.php, avrai già fatto e debuggato un ottimo strumento.
    IP-PBX management: http://www.easypbx.it

    Old account: 2126 messages
    Oldest account: 3559 messages

  10. #10
    Utente di HTML.it L'avatar di Fractals87
    Registrato dal
    Apr 2008
    Messaggi
    1,202
    Ok ho fatto un bel pò di prove sulla struttura da te indicata e mi pare veramente una figata.
    Data la sua facile comprensione l'ho preso aimè un pò come santo graal.
    Per quanto riguarda la gestione delle eccezzioni ho fatto in questo modo :

    Class db.php
    Codice PHP:
        public function connect(){ 

            if(
    $this->isConnected()) 
                return 
    true;//throw new Exception('Connessione già attiva'); 

            
    try{           
                
    $dsn $this->getDSN(); 
                
    $this->pdo = new PDO($dsn$this->username$this->password); 
                
    $this->pdo->setAttribute(PDO::ATTR_ERRMODEPDO::ERRMODE_EXCEPTION);       
                
    $this->pdo->setAttribute(PDO::MYSQL_ATTR_INIT_COMMAND"SET NAMES 'utf8'");               

                
    $this->connected true

            }catch(
    PDOException $ex){ 
                
    $this->pdo null
                
    $this->connected false;
                
    //$this->lastError = $ex->getMessage(); 
                
    $this->GestisciEccezzione();
            } 

            return 
    $this->isConnected(); 
        } 

        private function 
    GestisciEccezzione($ex){
            if(
    $this->conf->get('debug')){
                try{
                    
    $mail = new PHPMailer(true); //set true exception
                    
    $mail->Mailer $this->conf->get('mail.mailer'); 
                    
    $mail->Host $this->conf->get('mail.host');
                    
    $mail->Port $this->conf->get('mail.port');
                    
    $mail->Username $this->conf->get('mail.username');
                    
    $mail->Password $this->conf->get('mail.password');
                    
    $mail->FromName "ISDM"
                    
    $mail->AddAddress($this->conf->get('mail.dest_err'));
                    
    $mail->IsHTML(true);  
                    
    $mail->Subject =  "Error ISDM";
                    
    $mail->Body =  $ex->__tostring();
                    
    $mail->Send();
                }catch(
    phpmailerException $e){
                    echo 
    "ERRORE MAIL : 
    "
    ;
                    echo 
    $e->errorMessage();
                }
                
    header('location:'.$this->conf->get['application.root'].'login.php?Err= Si e\' verificato un errore interno. Il supporto tecnico e\' stato informato tramite mail.');        
            }else{
                echo 
    "Errore Intercettato : 
    "
    .$ex->__tostring()."
    "
    ;
                die();
            }
        } 
    Pagina test.php

    Codice PHP:
    <?php
    include_once "config/configuration.php"
    $conf = new Configuration('config/application.setting.ini'); 

    include_once 
    $conf->get['application.root']."class/PHPMailer_v5.1/class.phpmailer.php";
    include_once 
    $conf->get['application.root']."class/db.class.php";

    $db = new DB($conf);
    $db->connect();

    foreach(
    $db->fetchAll("SELECT user FROM utent") as $row){ 
        echo 
    $row['user']."
    "
    ;
        
    //print_r($row); 


    echo 
    "ciao";
    Più che altro non riesco a capire se risulta pratica corretta dichiarare nella pagina di test prima di tutto la classe phpmailer.php
    e poi tutte le altre classi, in modo da poter dichiarare al suo interno l'oggetto phpmailer
    Che mestiere difficile.....essere da soli ancora di più

Permessi di invio

  • Non puoi inserire discussioni
  • Non puoi inserire repliche
  • Non puoi inserire allegati
  • Non puoi modificare i tuoi messaggi
  •  
Powered by vBulletin® Version 4.2.1
Copyright © 2024 vBulletin Solutions, Inc. All rights reserved.