Code Coverage
 
Classes and Traits
Functions and Methods
Lines
Total
0.00% covered (danger)
0.00%
0 / 1
0.00% covered (danger)
0.00%
0 / 90
CRAP
0.00% covered (danger)
0.00%
0 / 982
TDAO
0.00% covered (danger)
0.00%
0 / 1
0.00% covered (danger)
0.00%
0 / 90
187922
0.00% covered (danger)
0.00%
0 / 981
 __construct
0.00% covered (danger)
0.00%
0 / 1
2
0.00% covered (danger)
0.00%
0 / 13
 setDbType
0.00% covered (danger)
0.00%
0 / 1
2
0.00% covered (danger)
0.00%
0 / 2
 getDbType
0.00% covered (danger)
0.00%
0 / 1
6
0.00% covered (danger)
0.00%
0 / 2
 setUsername
0.00% covered (danger)
0.00%
0 / 1
2
0.00% covered (danger)
0.00%
0 / 2
 getUsername
0.00% covered (danger)
0.00%
0 / 1
2
0.00% covered (danger)
0.00%
0 / 1
 setPassword
0.00% covered (danger)
0.00%
0 / 1
2
0.00% covered (danger)
0.00%
0 / 2
 getPassword
0.00% covered (danger)
0.00%
0 / 1
2
0.00% covered (danger)
0.00%
0 / 1
 setDatabase
0.00% covered (danger)
0.00%
0 / 1
2
0.00% covered (danger)
0.00%
0 / 2
 getDatabase
0.00% covered (danger)
0.00%
0 / 1
2
0.00% covered (danger)
0.00%
0 / 1
 setHost
0.00% covered (danger)
0.00%
0 / 1
2
0.00% covered (danger)
0.00%
0 / 2
 getHost
0.00% covered (danger)
0.00%
0 / 1
2
0.00% covered (danger)
0.00%
0 / 1
 setPort
0.00% covered (danger)
0.00%
0 / 1
2
0.00% covered (danger)
0.00%
0 / 2
 getPort
0.00% covered (danger)
0.00%
0 / 1
56
0.00% covered (danger)
0.00%
0 / 12
 setSchema
0.00% covered (danger)
0.00%
0 / 1
2
0.00% covered (danger)
0.00%
0 / 2
 getSchema
0.00% covered (danger)
0.00%
0 / 1
6
0.00% covered (danger)
0.00%
0 / 3
 setUtf8
0.00% covered (danger)
0.00%
0 / 1
2
0.00% covered (danger)
0.00%
0 / 2
 getUtf8
0.00% covered (danger)
0.00%
0 / 1
12
0.00% covered (danger)
0.00%
0 / 3
 connect
0.00% covered (danger)
0.00%
0 / 1
72
0.00% covered (danger)
0.00%
0 / 20
 query
0.00% covered (danger)
0.00%
0 / 1
2550
0.00% covered (danger)
0.00%
0 / 98
 getConn
0.00% covered (danger)
0.00%
0 / 1
12
0.00% covered (danger)
0.00%
0 / 4
 addField
0.00% covered (danger)
0.00%
0 / 1
30
0.00% covered (danger)
0.00%
0 / 14
 getField
0.00% covered (danger)
0.00%
0 / 1
6
0.00% covered (danger)
0.00%
0 / 4
 getFields
0.00% covered (danger)
0.00%
0 / 1
2
0.00% covered (danger)
0.00%
0 / 1
 setError
0.00% covered (danger)
0.00%
0 / 1
2
0.00% covered (danger)
0.00%
0 / 2
 getError
0.00% covered (danger)
0.00%
0 / 1
2
0.00% covered (danger)
0.00%
0 / 1
 getConnDsn
0.00% covered (danger)
0.00%
0 / 1
6
0.00% covered (danger)
0.00%
0 / 3
 getConnUtf8
0.00% covered (danger)
0.00%
0 / 1
6
0.00% covered (danger)
0.00%
0 / 3
 getConnDbType
0.00% covered (danger)
0.00%
0 / 1
6
0.00% covered (danger)
0.00%
0 / 3
 getConnSchema
0.00% covered (danger)
0.00%
0 / 1
6
0.00% covered (danger)
0.00%
0 / 3
 getSpecialChars
0.00% covered (danger)
0.00%
0 / 1
20
0.00% covered (danger)
0.00%
0 / 7
 utf8Encode
0.00% covered (danger)
0.00%
0 / 1
20
0.00% covered (danger)
0.00%
0 / 8
 utf8Decode
0.00% covered (danger)
0.00%
0 / 1
6
0.00% covered (danger)
0.00%
0 / 3
 prepareParams
0.00% covered (danger)
0.00%
0 / 1
240
0.00% covered (danger)
0.00%
0 / 34
 parseYMD
0.00% covered (danger)
0.00%
0 / 1
30
0.00% covered (danger)
0.00%
0 / 10
 parseDMY
0.00% covered (danger)
0.00%
0 / 1
30
0.00% covered (danger)
0.00%
0 / 10
 parseNumber
0.00% covered (danger)
0.00%
0 / 1
90
0.00% covered (danger)
0.00%
0 / 16
 parseFetchResult
0.00% covered (danger)
0.00%
0 / 1
420
0.00% covered (danger)
0.00%
0 / 35
 setCharset
0.00% covered (danger)
0.00%
0 / 1
2
0.00% covered (danger)
0.00%
0 / 2
 getCharset
0.00% covered (danger)
0.00%
0 / 1
30
0.00% covered (danger)
0.00%
0 / 9
 detectUTF8
0.00% covered (danger)
0.00%
0 / 1
30
0.00% covered (danger)
0.00%
0 / 8
 detectSpecialChar
0.00% covered (danger)
0.00%
0 / 1
42
0.00% covered (danger)
0.00%
0 / 10
 parseString
0.00% covered (danger)
0.00%
0 / 1
42
0.00% covered (danger)
0.00%
0 / 8
 setTableName
0.00% covered (danger)
0.00%
0 / 1
2
0.00% covered (danger)
0.00%
0 / 2
 getTableName
0.00% covered (danger)
0.00%
0 / 1
2
0.00% covered (danger)
0.00%
0 / 1
 getValidFieldType
0.00% covered (danger)
0.00%
0 / 1
42
0.00% covered (danger)
0.00%
0 / 12
 setMetadataDir
0.00% covered (danger)
0.00%
0 / 1
12
0.00% covered (danger)
0.00%
0 / 7
 getMetadataDir
0.00% covered (danger)
0.00%
0 / 1
12
0.00% covered (danger)
0.00%
0 / 3
 serializeFields
0.00% covered (danger)
0.00%
0 / 1
12
0.00% covered (danger)
0.00%
0 / 5
 unserializeFields
0.00% covered (danger)
0.00%
0 / 1
30
0.00% covered (danger)
0.00%
0 / 8
 loadTablesFromDatabase
0.00% covered (danger)
0.00%
0 / 1
42
0.00% covered (danger)
0.00%
0 / 14
 getMsSqlShema
0.00% covered (danger)
0.00%
0 / 1
6
0.00% covered (danger)
0.00%
0 / 4
 getSqlToFieldsFromOneStoredProcedureMySQL
0.00% covered (danger)
0.00%
0 / 1
2
0.00% covered (danger)
0.00%
0 / 4
 getSqlToFieldsFromOneStoredProcedureSqlServer
0.00% covered (danger)
0.00%
0 / 1
2
0.00% covered (danger)
0.00%
0 / 6
 getSqlToFieldsOneStoredProcedureFromDatabase
0.00% covered (danger)
0.00%
0 / 1
12
0.00% covered (danger)
0.00%
0 / 14
 loadFieldsOneStoredProcedureFromDatabase
0.00% covered (danger)
0.00%
0 / 1
30
0.00% covered (danger)
0.00%
0 / 10
 getSqlToFieldsFromDatabaseMySQL
0.00% covered (danger)
0.00%
0 / 1
2
0.00% covered (danger)
0.00%
0 / 3
 getSqlToFieldsFromDatabaseSqlServer
0.00% covered (danger)
0.00%
0 / 1
2
0.00% covered (danger)
0.00%
0 / 3
 getSqlToFieldsFromDatabasePostGres
0.00% covered (danger)
0.00%
0 / 1
2
0.00% covered (danger)
0.00%
0 / 3
 getSqlToFieldsFromDatabase
0.00% covered (danger)
0.00%
0 / 1
156
0.00% covered (danger)
0.00%
0 / 51
 loadFieldsOneTableFromDatabase
0.00% covered (danger)
0.00%
0 / 1
56
0.00% covered (danger)
0.00%
0 / 13
 loadFieldsFromDatabase
0.00% covered (danger)
0.00%
0 / 1
56
0.00% covered (danger)
0.00%
0 / 21
 setAutoincFieldName
0.00% covered (danger)
0.00%
0 / 1
2
0.00% covered (danger)
0.00%
0 / 2
 getAutoincFieldName
0.00% covered (danger)
0.00%
0 / 1
30
0.00% covered (danger)
0.00%
0 / 7
 getLastId
0.00% covered (danger)
0.00%
0 / 1
2
0.00% covered (danger)
0.00%
0 / 1
 getLastInsertId
0.00% covered (danger)
0.00%
0 / 1
132
0.00% covered (danger)
0.00%
0 / 25
 isPDO
0.00% covered (danger)
0.00%
0 / 1
6
0.00% covered (danger)
0.00%
0 / 3
 getBindType
0.00% covered (danger)
0.00%
0 / 1
6
0.00% covered (danger)
0.00%
0 / 17
 setAutoCommit
0.00% covered (danger)
0.00%
0 / 1
2
0.00% covered (danger)
0.00%
0 / 2
 getAutoCommit
0.00% covered (danger)
0.00%
0 / 1
6
0.00% covered (danger)
0.00%
0 / 1
 beginTransaction
0.00% covered (danger)
0.00%
0 / 1
20
0.00% covered (danger)
0.00%
0 / 8
 commit
0.00% covered (danger)
0.00%
0 / 1
20
0.00% covered (danger)
0.00%
0 / 8
 rollBack
0.00% covered (danger)
0.00%
0 / 1
20
0.00% covered (danger)
0.00%
0 / 7
 setFieldValue
0.00% covered (danger)
0.00%
0 / 1
6
0.00% covered (danger)
0.00%
0 / 5
 getFieldValue
0.00% covered (danger)
0.00%
0 / 1
12
0.00% covered (danger)
0.00%
0 / 4
 setPrimaryKey
0.00% covered (danger)
0.00%
0 / 1
90
0.00% covered (danger)
0.00%
0 / 21
 getPrimaryKeys
0.00% covered (danger)
0.00%
0 / 1
42
0.00% covered (danger)
0.00%
0 / 8
 save
0.00% covered (danger)
0.00%
0 / 1
42
0.00% covered (danger)
0.00%
0 / 17
 insert
0.00% covered (danger)
0.00%
0 / 1
30
0.00% covered (danger)
0.00%
0 / 7
 update
0.00% covered (danger)
0.00%
0 / 1
30
0.00% covered (danger)
0.00%
0 / 7
 delete
0.00% covered (danger)
0.00%
0 / 1
2
0.00% covered (danger)
0.00%
0 / 1
 insertValues
0.00% covered (danger)
0.00%
0 / 1
1406
0.00% covered (danger)
0.00%
0 / 99
 deleteValues
0.00% covered (danger)
0.00%
0 / 1
342
0.00% covered (danger)
0.00%
0 / 60
 updateValues
0.00% covered (danger)
0.00%
0 / 1
812
0.00% covered (danger)
0.00%
0 / 93
 getHasActiveTransaction
0.00% covered (danger)
0.00%
0 / 1
2
0.00% covered (danger)
0.00%
0 / 1
 getSqlCmd
0.00% covered (danger)
0.00%
0 / 1
2
0.00% covered (danger)
0.00%
0 / 1
 getSqlParams
0.00% covered (danger)
0.00%
0 / 1
2
0.00% covered (danger)
0.00%
0 / 1
 __call
0.00% covered (danger)
0.00%
0 / 1
42
0.00% covered (danger)
0.00%
0 / 10
 executeSql
0.00% covered (danger)
0.00%
0 / 1
2
0.00% covered (danger)
0.00%
0 / 3
 getFieldNames
0.00% covered (danger)
0.00%
0 / 1
12
0.00% covered (danger)
0.00%
0 / 6
 qfw
0.00% covered (danger)
0.00%
0 / 1
2
0.00% covered (danger)
0.00%
0 / 3
1<?php
2/*
3 * Formdin Framework
4 * Copyright (C) 2012 Ministério do Planejamento
5 * Criado por Luís Eugênio Barbosa
6 * Essa versão é um Fork https://github.com/bjverde/formDin
7 *
8 * ----------------------------------------------------------------------------
9 * This file is part of Formdin Framework.
10 *
11 * Formdin Framework is free software; you can redistribute it and/or
12 * modify it under the terms of the GNU Lesser General Public License version 3
13 * as published by the Free Software Foundation.
14 *
15 * This program is distributed in the hope that it will be useful,
16 * but WITHOUT ANY WARRANTY; without even the implied warranty of
17 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
18 * GNU General Public License for more details.
19 *
20 * You should have received a copy of the GNU Lesser General Public License version 3
21 * along with this program; if not,  see <http://www.gnu.org/licenses/>
22 * or write to the Free Software Foundation, Inc., 51 Franklin Street,
23 * Fifth Floor, Boston, MA  02110-1301, USA.
24 * ----------------------------------------------------------------------------
25 * Este arquivo é parte do Framework Formdin.
26 *
27 * O Framework Formdin é um software livre; você pode redistribuí-lo e/ou
28 * modificá-lo dentro dos termos da GNU LGPL versão 3 como publicada pela Fundação
29 * do Software Livre (FSF).
30 *
31 * Este programa é distribuído na esperança que possa ser útil, mas SEM NENHUMA
32 * GARANTIA; sem uma garantia implícita de ADEQUAÇÃO a qualquer MERCADO ou
33 * APLICAÇÃO EM PARTICULAR. Veja a Licença Pública Geral GNU/LGPL em português
34 * para maiores detalhes.
35 *
36 * Você deve ter recebido uma cópia da GNU LGPL versão 3, sob o título
37 * "LICENCA.txt", junto com esse programa. Se não, acesse <http://www.gnu.org/licenses/>
38 * ou escreva para a Fundação do Software Livre (FSF) Inc.,
39 * 51 Franklin St, Fifth Floor, Boston, MA 02111-1301, USA.
40 */
41
42include_once( 'autoload_formdin.php');
43class TDAO
44{
45    private $dbType      = null;
46    private $username    = null;
47    private $password    = null;
48    private $database    = null;
49    private $host        = null;
50    private $port        = null;
51    private $schema      = null;
52    private $utf8        = null;
53    private $error        = null;
54    private $conn        = null;
55    private $tableName    = null;
56    private $fields        = null;
57    private $specialChars = array();
58    private $charset = null;
59    private $metadataDir = null;
60    private $primaryKeys = null;
61    private $autoincFieldName = null;
62    private $lastId      = null;
63    private $autoCommit  = null;
64    private $hasActiveTransaction = false;
65    private $sqlCmd        = null;
66    private $sqlParams    = null;
67    private $cursor        = null;
68    private $eof        = null;
69
70    /**
71    * Classe de conexão com banco de dados e execução de comandos sql
72    * Permite conectar com vários tipos de banco de dados ao mesmo tempo
73    *
74    * Por padrão utilizará o arquivo conn_default.php ou includes/con_default.php
75    * caso não seja informado o parametro dbType. Quando o parametro dbType for
76    * informado, será então utlizado o arquivo "conn_????.php" referente.
77    * Exemplo: $dao = new TDAO(null,'postgres');
78    * será utilizado o arquivo conn_postgres.php
79    *
80    * Os arquivos de configurações devem possuir as seguintes definições:
81    *
82    * Exemplo Postgres
83    * $dbType = "postgres";
84    * $host = "192.168.1.140";
85    * $port = "5432";
86    * $database = "dbteste";
87    * $username = "postgres";
88    * $password = "123456";
89    * $utf8=1;
90    *
91    * Exemplo Mysql
92    * $dbType = "mysql";
93    * $host = "192.168.1.140";
94    * $port = "5432";
95    * $database = "dbteste";
96    * $username = "root";
97    * $password = "123456";
98    * $utf8=1;
99    *
100    * Exemplo Oracle
101    * $dbType = 'oracle';
102    * $host = '192.168.1.140';
103    * $port = '1521';
104    * $database = 'xe';
105    * $username = 'root';
106    * $password = '123456';
107    * $utf8=0;
108    *
109    * Exemplo Firebird/Interbase
110    * $dbType = "firebird";
111    * $host = '192.168.1.140';
112    * $port = null;
113    * $database = 'f:/fiirebird/DBTESTE.GDB';
114    * $username = "SYSDBA";
115    * $password = "masterkey";
116    * $utf8=1;
117    * return;
118    *
119    * Exemplo Sqlite
120    * $dbType = "sqlite";
121    * $database = "bdApoio.s3db";
122    * $utf8=0;
123    */
124
125    /**
126    * @param string $strTableName
127    * @param string $strDbType
128    * @param string $strUsername
129    * @param string $strPassword
130    * @param string $strDatabase
131    * @param string $strHost
132    * @param string $strPort
133    * @param string $strSchema
134    * @param boolean$boolUtf8
135    * @param string $strCharset
136    * @param boolean $boolAutoCommit
137    * @param string $strMetadataDir
138    * @return object TDAO
139    */
140    public function __construct( $strTableName = null
141                                , $strDbType = null
142                                , $strUsername = null
143                                , $strPassword = null
144                                , $strDatabase = null
145                                , $strHost = null
146                                , $strPort = null
147                                , $strSchema = null
148                                , $boolUtf8 = null
149                                , $strCharset = null
150                                , $boolAutoCommit = null
151                                , $strMetadataDir = null  )    {
152        $this->setTableName( $strTableName );
153        $this->setMetadataDir( $strMetadataDir );
154        $this->setDbType( $strDbType );
155        $this->setUserName( $strUsername );
156        $this->setPassword( $strPassword );
157        $this->setDataBase( $strDatabase );
158        $this->setHost( $strHost );
159        $this->setPort( $strPort );
160        $this->setSchema( $strSchema );
161        $this->setUtf8( $boolUtf8 );
162        $this->setCharset( $strCharset );
163        $this->setAutoCommit( $boolAutoCommit );
164    }
165
166    //----------------------------------------------------------------------------------
167    /**
168    * Define o tipo do banco de dados que será acessado.
169    * Os tipos de banco de dados suportados atualmente são:
170    * 
171    * 1) define('DBMS_MYSQL','MYSQL');
172    * 2) define('DBMS_POSTGRES','POSTGRES');
173    * 3) define('DBMS_FIREBIRD','FIREBIRD');
174    * 4) define('DBMS_SQLITE','SQLITE');
175    * 5) define('DBMS_ORACLE','ORACLE');
176    * 6) define('DBMS_SQLSERVER','SQLSERVER');
177    * 
178    * Obs: todos utilizam a extensão PDO exceto o Oracle que utiliza as funções OCI diretamente
179    *
180    * @param string $strNewValue
181    */
182    public function setDbType( $strNewValue = null ){
183        $this->dbType=$strNewValue;
184    }
185
186    /**
187    * Retorna o tipo do banco de dados que será acessado
188    *
189    * @return string;
190    */
191    public function getDbType(){
192        if( $this->conn ){
193            //return $this->getConnDbType();
194        }
195        return $this->dbType;
196    }
197
198    /**
199    * Define o nome do usuário que será utilizado para fazer a conexão com o banco de dados
200    *
201    * @param string $strNewValue
202    */
203    public function setUsername( $strNewValue = null ){
204        $this->username=$strNewValue;
205    }
206
207       /**
208    * Retorna o nome do usuário definido para fazer a conexão com o banco de dados.
209    *
210    * @return string $strNewValue
211    */
212    public function getUsername(){
213        return $this->username;
214    }
215    /**
216    * Define a senha de acesso do banco de dados
217    *
218    * @param string $strNewValue
219    */
220    public function setPassword( $strNewValue = null ){
221        $this->password=$strNewValue;
222    }
223
224    /**
225    * Retorna  a senha de acesso do banco de dados
226    *
227    */
228    public function getPassword(){
229        return $this->password;
230    }
231
232    /**
233    * Define o banco de dados onde estão as tabelas. No caso do oracle deve ser especificado
234    * o TNS, no caso do oracleXE seria XE
235    *
236    * @param string $strNewValue
237    */
238    public function setDatabase( $strNewValue = null ){
239        $this->database=$strNewValue;
240    }
241    /**
242    * Retorna o nome do banco de dados onde estão as tabelas
243    *
244    * @return string
245    */
246    public function getDatabase()
247    {
248        return $this->database;
249    }
250
251    /**
252    * Define o nome ou endereço IP do computador onde está instalado o banco de dados
253    *
254    * @param mixed $strNewValue
255    */
256    public function setHost( $strNewValue = null )
257    {
258        $this->host=$strNewValue;
259    }
260    /**
261    * Retorna o nome ou endereço IP do computador onde está instalado o banco de dados
262    *
263    * @return null
264    */
265    public function getHost()
266    {
267        return $this->host;
268    }
269
270    /**
271    * Define a porta de comunicação utilizada pelo banco de dados
272    * Quando não informada será utilzada as portas padrão de cada banco
273    *
274    * @param string $strNewValue
275    */
276    public function setPort( $strNewValue = null ){
277        $this->port=$strNewValue;
278    }
279    /**
280    * Retorna a porta de comunicação utilizada pelo banco de dados
281    *
282    */
283    public function getPort() {
284        if ( is_null( $this->port ) ) {
285            switch( strtolower( $this->getDbType() ) ) {
286                case 'postgre':
287                case DBMS_POSTGRES:
288                    $this->port='5432';
289                    break;
290
291                case DBMS_MYSQL:
292                    $this->port='3306';
293
294                    break;
295
296                case DBMS_SQLSERVER:
297                    $this->port='1433';
298
299                    break;
300
301                case DBMS_ORACLE:
302                    $this->port='1521';
303
304                    break;
305                }
306        }
307
308        return $this->port;
309    }
310
311    /**
312    * Define o nome do esquema dentro do banco de dados que deverã ser utilizado.
313    * Este método aplica somente ao banco de dados postgres
314    * Quando informado será adicionado ao path do banco de dados
315    *
316    * @param string $strNewValue
317    */
318    public function setSchema( $strNewValue = null )
319    {
320        $this->schema=$strNewValue;
321    }
322
323    /**
324    * Retorna o nome do esquema do banco de dados que será utilizado. Aplica-se somente
325    * ao banco de dados postgres.
326    *
327    * Quando informado será adicionado ao path do banco de dados
328    *
329    * @return string
330    */
331    public function getSchema()
332    {
333        if( $this->conn )
334        {
335            return $this->getConnSchema();
336        }
337        return $this->schema;
338    }
339
340    /**
341    * Define se o banco de dados está utilizando codificação UTF-8
342    *
343    * @param boolean $boolNewValue
344    */
345    public function setUtf8( $boolNewValue = null )
346    {
347        $this->utf8=$boolNewValue;
348    }
349    /**
350    * Retorna true ou false se o banco de dados está utilizando codificação UTF-8
351    *
352    */
353    public function getUtf8()
354    {
355        if( $this->conn )
356        {
357            return $this->getConnUtf8();
358        }
359        return ( ( $this->utf8 === false ) ? false : true );
360    }
361
362    /**
363    * Tenta fazer a conexão com o banco de dados retornando verdadeiro o falso
364    *
365    * @return boolean
366    */
367    public function connect() {
368        try {
369            if( ! $this->conn ){
370                $this->conn = TConnectionPool::connect( $this->getDbType()
371                                                      , $this->getUsername()
372                                                      , $this->getPassword()
373                                                      , $this->getDatabase()
374                                                      , $this->getHost()
375                                                      , $this->getPort()
376                                                      , $this->getSchema()
377                                                      , $this->getUtf8() );
378            }
379        }
380        catch( Exception $e ) {
381            $this->setError( $e->getMessage() );
382            return false;
383        }
384
385        if( $this->getMetadataDir())
386        {
387            if ( !is_array( $this->getFields() ) )
388            {
389                if ( !$this->unserializeFields() )
390                {
391                    $this->loadFieldsFromDatabase();
392                }
393            }
394            if( is_array($this->primaryKeys ) )
395            {
396                foreach($this->primaryKeys as $fieldName=>$boolTemp)
397                {
398                    $this->getField($fieldName)->primaryKey = 1;
399                }
400            }
401        }
402
403        return true;
404    }
405
406    /**
407    * Executa o comando sql recebido retornando o cursor ou verdadeiro o falso se a operação
408    * foi bem sucedida.
409    *
410    * @param string $sql
411    * @param mixed $params
412    * @param string $fetchMode
413    */
414    public function query( $sql = null, $params = null, $fetchMode = null )
415    {
416        $data=false;
417        $hasUserTransaction = $this->getHasActiveTransaction();
418        if ( !$this->getConn() )
419        {
420            return false;
421        }
422        try
423        {
424            if ( !is_null($params) && !is_array( $params ) )
425            {
426                $params = array($params);
427            }
428            $sql=trim( $sql );              // remover espaços do início e final
429            $sql=$this->utf8Decode( $sql ); // remover codificação utf8
430
431            if ( $this->getConnUtf8() )
432            {
433                $sql = $this->utf8Encode( $sql ); // aplicar codificação utf8
434            }
435            $params=$this->prepareParams( $params ); // aplicar/remover utf8 nos parâmetros
436        }
437        catch( Exception $e )
438        {
439            $this->setError( $e->getMessage() );
440            return false;
441        }
442
443        if ( $this->isPdo() )
444        {
445            if ( is_null( $fetchMode ) || ( $fetchMode != PDO::FETCH_ASSOC && $fetchMode != PDO::FETCH_CLASS ) )
446            {
447                $fetchMode = PDO::FETCH_ASSOC;
448            }
449
450            try
451            {
452                // trocar os "?" por ":p" para fazer o bind_by_name
453                if( is_array($params) && preg_match('/\?/',$sql)==1 )
454                {
455                    $keys = array_keys($params);
456                    foreach($keys as $v)
457                    {
458                        $sql = preg_replace('/\?/',':'.$v,$sql,1);
459                    }
460                }
461                $this->sqlCmd         = $sql;
462                $this->sqlParams     = $params;
463
464                $stmt=$this->getConn()->prepare( $sql );
465                if ( !$stmt )
466                {
467                    throw new Exception( 'Error preparing Sql.' );
468                }
469
470                if( preg_match( '/^select/i', $sql ) == 0 )
471                {
472                    $this->beginTransaction();
473                }
474                // fazer BINDS
475                if( is_array($params) )
476                {
477                    // formato de bindParam
478                    /*
479                    $paramIndex=1;
480                    forEach( $params  as $fieldName=>$fieldValue )
481                    {
482                        echo $fieldName.': ';
483                        $objField = $this->getField($fieldName);
484                        if( $objField )
485                        {
486                            $fieldType = $this->getValidFieldType($objField->fieldType);
487                            echo $fieldName.' = '.$fieldType.' Valor: '.$params[$fieldName].'<br>';
488                            switch( $fieldType )
489                            {
490                                    case 'binary':
491                                        $stmt->bindParam($paramIndex, $params[$fieldName], PDO::PARAM_LOB);
492                                    break;
493                                    //------------------------------------------------------------
494                                    case 'number':
495                                        $stmt->bindParam($paramIndex, $params[$fieldName]);
496                                    break;
497                                    //------------------------------------------------------------
498                                    default;
499                                    $stmt->bindParam($paramIndex, $params[$fieldName], PDO::PARAM_STR);
500                            }
501                        }
502                        else
503                        {
504                            $stmt->bindParam($paramIndex, $params[$fieldName], PDO::PARAM_STR);
505                        }
506                        $paramIndex++;
507                    }
508                    */
509                    // formato bindValues
510                    foreach( $params  as $fieldName=>$fieldValue )
511                    {
512                        $objField = $this->getField($fieldName);
513                        if( $objField )
514                        {
515                            $fieldType = $this->getValidFieldType($objField->fieldType);
516                            switch( $fieldType )
517                            {
518                                    case 'binary':
519                                        // ler o conteudo do arquivo se para o camp blob for informado o nome do arquivo
520                                        if( @file_exists($params[$fieldName] ) )
521                                        {
522                                            $params[$fieldName] = file_get_contents($params[$fieldName]);
523                                        }
524                                        $stmt->bindValue(':'.$fieldName, $params[$fieldName], PDO::PARAM_LOB);
525                                    break;
526                                    //------------------------------------------------------------
527                                    case 'number':
528                                        $stmt->bindValue(':'.$fieldName, $params[$fieldName]);
529                                    break;
530                                    //------------------------------------------------------------
531                                    default;
532                                    $stmt->bindValue(':'.$fieldName, $params[$fieldName], PDO::PARAM_STR);
533                            }
534                        }
535                        else
536                        {
537                            if( is_integer($params[$fieldName] ))
538                            {
539                                    $stmt->bindValue(':'.$fieldName, $params[$fieldName], PDO::PARAM_INT);
540                            }
541                            else if( is_numeric($params[$fieldName] ) )
542                            {
543                                $stmt->bindValue(':'.$fieldName, $params[$fieldName]);
544                            }
545                            else
546                            {
547                                $stmt->bindValue(':'.$fieldName, $params[$fieldName], PDO::PARAM_STR);
548                            }
549                        }
550                    }
551                    $params=null;
552                }
553                $result=$stmt->execute( $params );
554                if ( !$result )
555                {
556                    throw new Exception( 'Error executing Sql!' );
557                }
558            }
559            catch( Exception $e )
560            {
561                $this->setError( $e->getMessage() );
562                return false;
563            //throw $e;
564            }
565            if( $this->getAutoCommit() && ! $hasUserTransaction )
566            {
567                $this->commit();
568            }
569            $data=true;
570            try
571            {
572                if ( preg_match( '/^select/i', $sql ) > 0 || preg_match( '/returning /i', $sql ) > 0 || preg_match( '/^with /i', $sql ) > 0 )
573                {
574                    $data = $stmt->fetchAll( $fetchMode );
575                }
576            }
577            catch( Exception $e )
578            {
579                $data=false;
580                $this->setError( $e->getMessage() );
581            }
582
583            $stmt->closeCursor();
584        }
585        else
586        {
587            $conn=$this->getConn()->connection;
588
589            if ( $this->getDbType() == DBMS_ORACLE )
590            {
591                if ( is_null( $fetchMode ) || ( $fetchMode != 'FETCH_ASSOC' && $fetchMode != 'FETCH_CLASS' ) )
592                {
593                    $fetchMode = 'FETCH_ASSOC'; //OCI_FETCHSTATEMENT_BY_ROW;
594                }
595
596                try
597                {
598                    // trocar os "?" por ":p" para fazer o bind_by_name
599                    if( is_array($params) && preg_match('/\?/',$sql)==1 )
600                    {
601                        $keys = array_keys($params);
602                        foreach($keys as $v)
603                        {
604                            $sql = preg_replace('/\?/',':'.$v,$sql,1);
605                        }
606                    }
607                    $stmt = oci_parse( $conn, $sql );
608                    $descriptors=null;
609
610                    if ( is_array( $params ) )
611                    {
612                        foreach( $params as $fieldName => $fieldValue )
613                        {
614                            $objField = $this->getField( $fieldName );
615                            if ( $objField )
616                            {
617                                $bindType=$this->getBindType( $objField->fieldType );
618                                oci_bind_by_name( $stmt, ':' . $fieldName, $params[ $fieldName ], $objField->size, $bindType );
619                            }
620                            else
621                            {
622                                oci_bind_by_name( $stmt, ':' . $fieldName, $params[$fieldName] );
623                            }
624                        }
625                    }
626
627                    if ( !@oci_execute( $stmt, OCI_NO_AUTO_COMMIT ) ) // OCI_DEFAULT = não commit
628                    {
629                        $e=oci_error( $stmt );
630
631                        throw new Exception( 'Sql error ' . $e[ 'message' ] );
632                    }
633
634                    if ( preg_match( '/^select/i', $sql ) > 0 )
635                    {
636                        if ( $fetchMode == 'FETCH_ASSOC' )
637                        {
638                            oci_fetch_all( $stmt, $data, null, null, OCI_FETCHSTATEMENT_BY_ROW + OCI_RETURN_NULLS );
639                        }
640                        else if( $fetchMode == 'FETCH_CLASS' )
641                        {
642                            $data=array();
643
644                            while( $row = oci_fetch_object( $stmt ) )
645                            {
646                                array_push( $data, $row );
647                            }
648                        }
649                    }
650                }
651                catch( Exception $e )
652                {
653                    $data=false;
654                    $this->setError( $e->getMessage() );
655                }
656
657                oci_free_statement( $stmt );
658            //oci_close($conn);
659            }
660        }
661
662        if ( $data && is_array( $data ) )
663        {
664            $data = $this->parseFetchResult( $data );
665        }
666
667        return $data;
668    }
669
670    /**
671    * Retorna a instância do objeto da conexão com o banco de dados
672    *
673    * @return object
674    */
675    public function getConn()
676    {
677        if ( is_null( $this->conn ) )
678        {
679            if ( !$this->connect() )
680            {
681                return false;
682            }
683        }
684
685        return $this->conn;
686    }
687
688    /**
689    * Adiciona campos da tabela ao array de campos que serão utilizados
690    * nos binds e nos métodos save, insert e delete da classe
691    *
692    * @param string $strFieldName
693    * @param string $strFieldType
694    * @param integer $intSize
695    * @param integer $intPrecision
696    * @param string $strDefaultValue
697    * @param boolean $boolNullable
698    * @param boolean $boolAutoincrement
699    * @param boolean $boolPrimaryKey
700    */
701    public function addField( $strFieldName, $strFieldType = null, $intSize = null, $intPrecision = null, $strDefaultValue = null, $boolNullable = null, $boolAutoincrement = null, $boolPrimaryKey = null )
702    {
703        $strFieldType         =( is_null( $strFieldType ) ? 'varchar':$strFieldType);
704        $boolAutoincrement    =( is_null( $boolAutoincrement ) ? 0 : $boolAutoincrement );
705        $boolNullable       =( is_null( $boolNullable ) ? 1 : $boolNullable );
706        $boolPrimaryKey     =( is_null( $boolPrimaryKey ) ? 0 : $boolPrimaryKey );
707        $this->fields[ strtoupper( $strFieldName )]=(object)array
708            (
709            'fieldName'     => $strFieldName,
710            'fieldType'     => $strFieldType,
711            'size'          => $intSize,
712            'precision'     => $intPrecision,
713            'defaultValue'  => $strDefaultValue,
714            'nullable'      => $boolNullable,
715            'autoincrement' => $boolAutoincrement,
716            'primaryKey'    => $boolPrimaryKey,
717            'value'            => null
718            );
719    }
720
721    /**
722    * Retorna o objeto do campo solictado
723    * Se o campo não existier retorna null
724    *
725    * @param string $strFieldName
726    */
727    public function getField( $strFieldName )
728    {
729        $strFieldName=strtoupper( $strFieldName );
730
731        if ( isset( $this->fields[ $strFieldName ] ) )
732        {
733            return $this->fields[ $strFieldName ];
734        }
735
736        return null;
737    }
738
739    /**
740    * Retorna o array de objetos dos campos da tabela
741    *
742    */
743    public function getFields()
744    {
745        return $this->fields;
746    }
747    /**
748    * Defina a mensagem de erro
749    *
750    * @param string $strError
751    */
752    public function setError( $strError = null )
753    {
754        $this->error=$strError;
755    }
756    /**
757    * Retorna a mensagem de erro atual
758    *
759    */
760    public function getError()
761    {
762        return $this->error;
763    }
764
765    /**
766    * Retorna a string dsn utilizada na conexão PDO
767    *
768    * @return string
769    */
770    public function getConnDsn()
771    {
772        if ( $this->getConn() )
773        {
774            return $this->getConn()->dsn;
775        }
776
777        return null;
778    }
779
780    /**
781    * Retorna se o banco de dados está utilizando a codificação UTF-8
782    *
783    */
784    public function getConnUtf8(){
785        if ( $this->getConn() ){
786            return $this->getConn()->utf8;
787        }
788        return true;
789    }
790    
791    /**
792    * Retorna o tipo de banco de dados que está sendo utilizado.
793    * Ex: mysql, postgres, oracle...
794    *
795    * @return string
796    */
797    public function getConnDbType(){
798        if ( $this->getConn() ) {
799            return $this->getConn()->dbType;
800        }
801        return null;
802    }
803
804    /**
805    * Retorna o nome do esquema utilizado pela conexão postgres somente
806    * @return string
807    */
808    public function getConnSchema()
809    {
810        if ( $this->getConn() )
811        {
812            return $this->getConn()->schema;
813        }
814
815        return null;
816    }
817
818    /**
819    * Retorna os caracteres considerados especias
820    *
821    * @return array
822    */
823    public function getSpecialChars()
824    {
825        if ( count( $this->specialChars ) == 0 )
826        {
827            $this->specialChars=array
828                (
829                'Ã',
830                'Â'
831                );
832
833            for( $i = 127; $i < 256; $i++ )
834            {
835                $char = chr( $i );
836
837                if ( !preg_match( '/Â|Ã/', $char ) )
838                {
839                    $this->specialChars[] = $char;
840                }
841            }
842        }
843
844        return $this->specialChars;
845    }
846
847    /**
848    * Transforma os caracteres epeciais em seus carateres utf8 relacionados
849    *
850    * @param string $str
851    */
852    public function utf8Encode( $str = null )
853    {
854        if ( is_null( $str ) || $str == '' )
855        {
856            return $str;
857        }
858
859        $result='';
860        $this->utf8Decode( $str );
861
862        $len  = StringHelper::strlen( $str );
863        for( $i = 0; $i < $len; $i++ ){
864            $result .= utf8_encode( substr( $str, $i, 1 ) );
865        }
866
867        return $result;
868    }
869
870    /**
871    * Transforma o caracteres codificados em utf-8 no caractere especial relacionado
872    *
873    * @param string $str
874    */
875    public function utf8Decode( $str = null )
876    {
877        foreach( $this->getSpecialChars()as $char )
878        {
879            $str = preg_replace( '/' . utf8_encode( $char ) . '/', $char, $str );
880        }
881
882        return $str;
883    }
884
885    /**
886    * Processa o array de parametros aplicando/removendo codificação utf8, convertendo
887    * datae números no formado correto de acordo com o banco de dados.
888    *
889    * Se $boolBind for true ( padrão) o retorno será o array associativo (key=>value ) quando
890    * este for recebido neste formato,  se false o resultdo será convertido em um array indexado de 0 a N
891    *
892    * @param mixed $mixParams
893    * @param boolean $boolBind
894    */
895    public function prepareParams( $mixParams = null, $boolBind = true )
896    {
897        if ( is_numeric( $mixParams ) )
898        {
899            return $this->parseNumber( $mixParams );
900        }
901        else if( is_string( $mixParams ) )
902        {
903            if ( $this->getConnUtf8() )
904            {
905                $mixParams=trim( $mixParams );
906                $mixParams=$this->utf8Decode( $mixParams ); // remover utf8
907                return $this->utf8Encode( $mixParams );
908            }
909
910            return $this->utf8Decode( $mixParams );
911        }
912        else if( is_array( $mixParams ) )
913        {
914            $result=array();
915
916            foreach( $mixParams as $k => $item )
917            {
918                if ( is_numeric( $item ) )
919                {
920                    if ( !$boolBind )
921                    {
922                        array_push( $result, $this->prepareParams( $item, $boolBind ) );
923                    }
924                    else
925                    {
926                        $result[ $k ] = $this->prepareParams( $item, $boolBind );
927                    }
928                }
929                else
930                {
931                    $objField=$this->getField( $k );
932                    $fieldType=null;
933                    if ( ! is_null( $objField ) )
934                    {
935                        $fieldType=$this->getValidFieldType( $objField->fieldType );
936                        if ( $fieldType == 'date' )
937                        {
938                            if ( $this->getDbType() == DBMS_ORACLE )
939                            {
940                                $item = $this->parseDMY( $item );
941                            }
942                            else
943                            {
944                                $item = $this->parseYMD( $item );
945                            }
946                        }
947                        elseif( $fieldType == 'number' )
948                        {
949                            $item = $this->parseNumber( $item );
950                        }
951                    }
952
953                    if ( ! $boolBind )
954                    {
955                        if ( $fieldType != 'binary' )
956                        {
957                            $item = $this->prepareParams( $item, $boolBind );
958                        }
959                        array_push( $result, $item );
960                    }
961                    else
962                    {
963                        if ( $fieldType != 'binary' )
964                        {
965                            $item = $this->prepareParams( $item, $boolBind );
966                        }
967                        $result[ $k ]=$item;
968                    }
969                }
970            }
971            return $result;
972        }
973        return $mixParams;
974    }
975    /**
976    * Retorna a data invertida no formato Ano, MÊs e Dia.
977    *
978    * @param string $date
979    */
980    public function parseYMD( $strDate = null )
981    {
982        if ( is_null( $strDate ) )
983        {
984            return $strDate;
985        }
986
987        $strDate =preg_replace( '/\//', '-', $strDate ); // trocar barra para hifem
988        $aTemp=explode( ' ', $strDate );              // separar horas
989        $strDate =$aTemp[ 0 ];
990        $time =( isset( $aTemp[ 1 ] ) ? $aTemp[ 1 ] : null );
991        $aTemp=explode( '-', $strDate );
992
993        if ( !preg_match( '/^[0-9]{4}/', $strDate ) )
994        {
995            $strDate = $aTemp[ 2 ] . '-' . $aTemp[ 1 ] . '-' . $aTemp[ 0 ];
996        }
997
998        return $strDate . ( is_null( $time ) ? '' : ' ' . $time );
999    }
1000    /**
1001    * Retorna a data no formato normal de Dia, Mês e Ano
1002    *
1003    * @param string $date
1004    */
1005    public function parseDMY( $strDate = null )
1006    {
1007        if ( is_null( $strDate ) )
1008        {
1009            return $strDate;
1010        }
1011
1012        $strDate =preg_replace( '/\//', '-', $strDate ); // trocar barra para hifem
1013        $aTemp=explode( ' ', $strDate );              // separar horas
1014        $strDate =$aTemp[ 0 ];
1015        $time =( isset( $aTemp[ 1 ] ) ? $aTemp[ 1 ] : null );
1016        $aTemp=explode( '-', $strDate );
1017
1018        if ( preg_match( '/^[0-9]{4}/', $strDate ) )
1019        {
1020            $strDate = $aTemp[ 2 ] . '-' . $aTemp[ 1 ] . '-' . $aTemp[ 0 ];
1021        }
1022
1023        return $strDate . ( is_null( $time ) ? '' : ' ' . $time );
1024    }
1025
1026    /**
1027    * Corrige o valor formatdo para numero decimal válido, colocando o ponto no lugar
1028    * da virgula
1029    *
1030    * @param string $value
1031    */
1032    public function parseNumber( $strValue = null)
1033    {
1034        if ( preg_match( '/\,/', $strValue ) == 1 )
1035        {
1036            $posComma=strpos( $strValue, ',' );
1037            $qtdComma=substr_count( $strValue, ',' );
1038            $posPoint=strpos( $strValue, '.' );
1039
1040            if ( $posPoint === false && $qtdComma > 1 )
1041            {
1042                $strValue = preg_replace( '/\,/', '', $strValue );
1043            }
1044            else if( $posPoint == 0 && $posComma > 0 )
1045            {
1046                $strValue = preg_replace( '/\,/', '.', $strValue );
1047            }
1048            else if( $posComma > $posPoint )
1049            {
1050                $strValue=preg_replace( '/\./', '', $strValue );
1051                $strValue=preg_replace( '/\,/', '.', $strValue );
1052            }
1053            else if( $posComma < $posPoint )
1054            {
1055                $strValue = preg_replace( '/\,/', '', $strValue );
1056            }
1057        }
1058
1059        if ( $this->getDbType() == DBMS_ORACLE )
1060        {
1061            $strValue = preg_replace( '/\./', ',', $strValue );
1062        }
1063
1064        return $strValue;
1065    }
1066
1067    /**
1068    * Processa o resultado da consulta sql aplivando/removendo utf-8, ajustando números e datas
1069    * de acordo com o tipo da coluna
1070    *
1071    * @param mixed $data
1072    */
1073    public function parseFetchResult( $data = null )
1074    {
1075        //return $data;
1076        if ( is_null( $data ) )
1077        {
1078            return $data;
1079        }
1080
1081        if ( !is_array( $data ) )
1082        {
1083            return $data;
1084        }
1085
1086        if ( isset( $data[ 0 ] ) )
1087        {
1088            if ( is_object( $data[ 0 ] ) )
1089            {
1090                if ( $this->getFields() )
1091                {
1092                    foreach( $data as $k => $obj )
1093                    {
1094                        foreach( $this->getFields()as $fieldName => $objField )
1095                        {
1096                            $f         = $objField->fieldName;
1097                            $fieldValue=null;
1098
1099                            if ( !isset( $obj->$f ) )
1100                            {
1101                                $f=strtolower( $f );
1102
1103                                if ( !isset( $obj->$f ) )
1104                                {
1105                                    $f = null;
1106                                }
1107                            }
1108
1109                            if ( !is_null( $f ) )
1110                            {
1111                                $fieldType=$this->getValidFieldType( $objField->fieldType );
1112
1113                                if ( $fieldType == 'date' )
1114                                {
1115                                    $fieldValue = $this->parseDMY( $obj->$f );
1116                                }
1117                                else if( $fieldType == 'text' )
1118                                {
1119                                    $fieldValue = $this->parseString( $obj->$f );
1120                                }
1121
1122                                if ( !is_null( $fieldValue ) )
1123                                {
1124                                    $obj->$f = $fieldValue;
1125                                }
1126                            }
1127                        }
1128                    }
1129                }
1130            }
1131            else if( is_array( $data[ 0 ] ) )
1132            {
1133                foreach( $data as $k => $arr )
1134                {
1135                    foreach( $arr as $fieldName => $value )
1136                    {
1137                        if ( $this->getField( $fieldName ) )
1138                        {
1139                            $objField =$this->getField( $fieldName );
1140                            $fieldType=$this->getValidFieldType( $objField->fieldType );
1141                            if ( $fieldType == 'date' )
1142                            {
1143                                $data[ $k ][ $fieldName ] = $this->parseDMY( $value );
1144                            }
1145                            else if( $fieldType == 'string' )
1146                            {
1147                                $data[ $k ][ $fieldName ] = $this->parseString( $value );
1148                            }
1149                        }
1150                        else
1151                        {
1152                            $data[ $k ][ $fieldName ] = $this->parseString( $value );
1153                        }
1154                    }
1155                }
1156            }
1157        }
1158        return $data;
1159    }
1160    /**
1161    * Define o tipo de codificação que está sendo utilizada no browser. Padrão é utf-8
1162    * Pode ser definido de maneira global utilizando a constante CHARSET
1163    * Exemplo: setCharset('utf-8'); ou setCharset('iso-8859');
1164    *
1165    * @example setCharset('utf-8'),setCharset('iso-8859');
1166    * @param string $strNewValue
1167    */
1168    public function setCharset( $strNewValue = null )
1169    {
1170        $this->charset=$strNewValue;
1171    }
1172    /**
1173    * REtorna o tipo de codificação que está sendo utilizada no browser
1174    *
1175    * @return string
1176    */
1177    public function getCharset()
1178    {
1179        if ( is_null( $this->charset ) )
1180        {
1181            if ( defined( 'CHARSET' ) )
1182            {
1183                $this->charset = CHARSET;
1184            }
1185            else
1186            {
1187                $this->charset = 'iso-8859';
1188            }
1189        }
1190
1191        if ( strtolower( $this->charset ) == 'utf8' )
1192        {
1193            $this->charset = 'utf-8';
1194        }
1195
1196        if ( !defined( 'CHARSET' ) )
1197        {
1198            define('CHARSET',$this->charset);
1199        }
1200        return strtolower( $this->charset );
1201    }
1202
1203    /**
1204    * Retorna true/false se string estiver na codificação UTF-8
1205    *
1206    * @param string $strValue
1207    * @return boolean
1208    */
1209    public function detectUTF8( $strValue = null )
1210    {
1211        if ( is_numeric( $strValue ) || !is_string( $strValue ) )
1212        {
1213            return false;
1214        }
1215
1216        $result=false;
1217
1218        foreach( $this->getSpecialChars()as $k => $v )
1219        {
1220            if ( preg_match( '/' . utf8_encode( $v ) . '/', $strValue ) )
1221            {
1222                $result=true;
1223                break;
1224            }
1225        }
1226
1227        return $result;
1228    }
1229    /**
1230    * Método para verificar se existe algum caractere especial na string
1231    *
1232    * @param mixed $strValue
1233    * @return boolean
1234    */
1235    public function detectSpecialChar( $strValue = null )
1236    {
1237        if ( is_numeric( $strValue ) || !is_string( $strValue ) )
1238        {
1239            return false;
1240        }
1241
1242        // se tiver na codificação utf-8 retornar false
1243        if ( $this->detectUTF8( $strValue ) )
1244        {
1245            return false;
1246        }
1247
1248        $result=false;
1249
1250        foreach( $this->getSpecialChars()as $k => $v )
1251        {
1252            if ( preg_match( '/' . $v . '/', $strValue ) )
1253            {
1254                $result=true;
1255                break;
1256            }
1257        }
1258
1259        return $result;
1260    }
1261
1262    /**
1263    * Método para converter a string para utf-8 ou ascii dependendo
1264    * das configurações do banco de dados e do charset definido
1265    *
1266    * @param string $strValue
1267    */
1268    public function parseString( $strValue = null )
1269    {
1270        if ( !is_string( $strValue ) || is_numeric( $strValue ) )
1271        {
1272            return $strValue;
1273        }
1274
1275        if ( $this->getCharset() == 'utf-8' )
1276        {
1277            if ( $this->detectSpecialChar( $strValue ) )
1278            {
1279                $strValue = $this->utf8Encode( $strValue );
1280            }
1281        }
1282        else
1283        {
1284            if ( $this->detectUTF8( $strValue ) )
1285            {
1286                $strValue = $this->utf8Decode( $strValue );
1287            }
1288        }
1289
1290        return $strValue;
1291    }
1292
1293    /**
1294    * Define o nome da tabela do banco de dados que será utizizada nos
1295    * comando insert, save, delete ...
1296    *
1297    * @param string $strNewValue
1298    */
1299    public function setTableName( $strNewValue = null )
1300    {
1301        $this->tableName=$strNewValue;
1302    }
1303    /**
1304    * Retorna o nome da tabela que está sendo utilizada nos comandos
1305    * insert, delete, save ...
1306    *
1307    */
1308    public function getTableName()
1309    {
1310        return $this->tableName;
1311    }
1312
1313    /**
1314    * Converte o tipo de campo da coluna da tabela para um tipo de campo padrão da classe
1315    *
1316    * @param string $strFieldType
1317    * @return string
1318    */
1319    public function getValidFieldType( $strFieldType = null )
1320    {
1321        list( $strFieldValue )=explode( ' ', $strFieldType );
1322
1323        if ( is_null( $strFieldType ) )
1324        {
1325            return null;
1326        }
1327
1328        if ( preg_match( '/long|clob|char|varchar|varchar2|text|charactervarying/i', $strFieldType ) )
1329        {
1330            return 'string';
1331        }
1332
1333        if ( preg_match( '/decimal|real|float|numeric|number|int|int64|integer|double|smallint|bigint/i', $strFieldType ) )
1334        {
1335            return 'number';
1336        }
1337
1338        if ( preg_match( '/date|datetime|timestamp/i', $strFieldType ) )
1339        {
1340            return 'date';
1341        }
1342
1343        if ( preg_match( '/blob|bytea/i', $strFieldType ) )
1344        {
1345            return 'binary';
1346        }
1347
1348        return $strFieldType;
1349    }
1350
1351    /**
1352    * Retorna o diretório/pasta onde será armazenada as informações dos campos
1353    * extraídos das tabela
1354    *
1355    * @param string $strNewValue
1356    */
1357    public function setMetadataDir( $strNewValue = null )
1358    {
1359        $this->metadataDir=trim( $strNewValue ) . '/';
1360        $this->metadataDir=preg_replace( '/\/\//', '', $this->metadataDir ) . '/';
1361
1362        if ( !is_null( $strNewValue ) && !file_exists( $strNewValue ) )
1363        {
1364            $oldumask=umask( 0 );
1365            @mkdir( $strNewValue, 0755, true );
1366            umask( $oldumask );
1367        }
1368    }
1369    /**
1370    * Retorna o nome do diretório/pasta onde serão armazendas as informações dos campos
1371    * das tabelas
1372    *
1373    * @return string;
1374    */
1375    public function getMetadataDir()
1376    {
1377        if ( !is_null( $this->metadataDir ) && file_exists( $this->metadataDir ) )
1378        {
1379            return preg_replace( '/\/\//', '/', $this->metadataDir . '/' );
1380        }
1381
1382        return null;
1383    }
1384
1385    /**
1386    * Serialize e salva os campos no diretório/pasta de metadados
1387    *
1388    * @return null
1389    */
1390    public function serializeFields()
1391    {
1392        if ( $this->getMetadataDir() && $this->getTableName() )
1393        {
1394            $filename = $this->getMetadataDir() . $this->getConnDbType() . '-' . $this->getTableName() . '.ser';
1395            $data = serialize( $this->getFields() );
1396            file_put_contents( $filename, $data );
1397        }
1398    }
1399    /**
1400    * Desserializa as definições dos campos de uma tabela que foram salvos no diretório/pasta
1401    * de metadados e carrega o array fields da classe
1402    *
1403    * @return boolean
1404    */
1405    public function unserializeFields()
1406    {
1407        $result=false;
1408
1409        if ( $this->getMetadataDir() && $this->getTableName() )
1410        {
1411            $fileName=$this->getMetadataDir() . $this->getConnDbType() . '-' . $this->getTableName() . '.ser';
1412
1413            if ( file_exists( $fileName ) )
1414            {
1415                $this->fields=unserialize( file_get_contents( $fileName ) );
1416
1417                if ( is_array( $this->fields ) )
1418                {
1419                    $result = true;
1420                }
1421            }
1422        }
1423
1424        return $result;
1425    }
1426    
1427    public function loadTablesFromDatabase() {
1428        //$DbType = $this->getConnDbType();
1429        $DbType = $this->getDbType();
1430        $sql = null;
1431        switch( $DbType ) {
1432            case DBMS_SQLITE:
1433                $sql = 'SELECT 
1434                            \'\' as TABLE_SCHEMA
1435                            ,name as TABLE_NAME 
1436                            ,\'\' as COLUMN_QTD
1437                            ,upper(type) as TABLE_TYPE
1438                        FROM sqlite_master where type in (\'table\', \'view\')';
1439            break;
1440            //--------------------------------------------------------------------------------
1441            case DBMS_MYSQL:
1442                $sql = "select vg.TABLE_SCHEMA
1443                              ,vg.TABLE_NAME
1444                              ,vg.COLUMN_QTD
1445                              ,vg.TABLE_TYPE
1446                        from
1447                        (                        
1448                            select vt.TABLE_SCHEMA
1449                                  ,vt.TABLE_NAME
1450                                  ,count(*) as COLUMN_QTD
1451                                  ,vt.TABLE_TYPE
1452                            from
1453                            (
1454                                SELECT t.TABLE_SCHEMA
1455                                      ,t.TABLE_NAME
1456                                      ,case when upper(t.TABLE_TYPE) = 'BASE TABLE' then 'TABLE' else upper(t.TABLE_TYPE) end  as TABLE_TYPE
1457                                FROM INFORMATION_SCHEMA.TABLES as t
1458                                    ,INFORMATION_SCHEMA.COLUMNS as c
1459                                WHERE t.TABLE_NAME = c.TABLE_NAME 
1460                                 and  t.TABLE_SCHEMA = c.TABLE_SCHEMA
1461                                 and (t.TABLE_TYPE = 'BASE TABLE' OR t.TABLE_TYPE = 'VIEW')
1462                                 and t.TABLE_SCHEMA not in ('sys','phpmyadmin','performance_schema','mysql','information_schema')
1463                             ) as vt
1464                             group by vt.TABLE_SCHEMA
1465                                     ,vt.TABLE_NAME
1466                                     ,vt.TABLE_TYPE
1467                                     
1468                            union
1469                        
1470                            select vp.TABLE_SCHEMA
1471                                  ,vp.TABLE_NAME
1472                                  ,count(*) as COLUMN_QTD
1473                                  ,'PROCEDURE' as TABLE_TYPE
1474                            from
1475                            (
1476                                select p.SPECIFIC_SCHEMA as TABLE_SCHEMA
1477                                      ,p.SPECIFIC_NAME as TABLE_NAME
1478                                      ,p.routine_type as TABLE_TYPE
1479                                from information_schema.routines as r
1480                                left join information_schema.parameters as p
1481                                          on p.specific_schema = r.routine_schema
1482                                          and p.specific_name = r.specific_name
1483                                where r.routine_schema not in ('sys','phpmyadmin','information_schema','mysql', 'performance_schema')
1484                                and p.routine_type = 'PROCEDURE'
1485                            ) as vp
1486                            group by vp.TABLE_SCHEMA
1487                                    ,vp.TABLE_NAME
1488                                    ,vp.TABLE_TYPE
1489                        ) as vg
1490                        order by 
1491                                 vg.TABLE_SCHEMA
1492                                ,vg.TABLE_TYPE
1493                                ,vg.TABLE_NAME";
1494            break;
1495            //--------------------------------------------------------------------------------
1496            case DBMS_SQLSERVER:
1497                $sql = "select 
1498                        TABLE_SCHEMA
1499                        ,TABLE_NAME
1500                        ,COLUMN_QTD
1501                        ,TABLE_TYPE
1502                        from (
1503                        SELECT qtd.TABLE_SCHEMA
1504                                ,qtd.TABLE_NAME
1505                                ,qtd.COLUMN_QTD
1506                                ,case ty.TABLE_TYPE WHEN 'BASE TABLE' THEN 'TABLE' ELSE ty.TABLE_TYPE end as TABLE_TYPE
1507                        FROM
1508                            (SELECT TABLE_SCHEMA
1509                                    ,TABLE_NAME
1510                                    ,COUNT(TABLE_NAME) COLUMN_QTD
1511                            FROM INFORMATION_SCHEMA.COLUMNS c
1512                            where c.TABLE_SCHEMA <> 'METADADOS'
1513                            group by TABLE_SCHEMA, TABLE_NAME
1514                            ) as qtd
1515                            ,(SELECT TABLE_SCHEMA
1516                                    , TABLE_NAME
1517                                    , TABLE_TYPE
1518                            FROM INFORMATION_SCHEMA.TABLES i
1519                            where I.TABLE_SCHEMA <> 'METADADOS'
1520                            ) as ty
1521                        where qtd.TABLE_SCHEMA = ty.TABLE_SCHEMA
1522                        and qtd.TABLE_NAME = ty.TABLE_NAME
1523                        
1524                        UNION
1525                        
1526                         SELECT Schema_name(schema_id)   AS TABLE_SCHEMA,
1527                               SO.NAME                   AS TABLE_NAME,       
1528                               count(*)                  AS COLUMN_QTD,
1529                               CASE SO.type_desc 
1530                               WHEN  'SQL_STORED_PROCEDURE' THEN 'PROCEDURE'
1531                               ELSE 'FUNCTION' 
1532                               END AS TABLE_TYPE       
1533                        FROM   sys.objects AS SO
1534                               INNER JOIN sys.parameters AS P
1535                                       ON SO.object_id = P.object_id
1536                        WHERE  SO.object_id IN (SELECT object_id
1537                                                FROM   sys.objects
1538                                                WHERE  type IN ( 'P', 'FN' ))
1539                        group by schema_id, SO.NAME, SO.type_desc
1540                        ) as res
1541                        order by res.TABLE_SCHEMA
1542                               , res.TABLE_TYPE
1543                               , res.TABLE_NAME";
1544            break;
1545            //--------------------------------------------------------------------------------
1546            case DBMS_POSTGRES:
1547                $sql = "SELECT qtd.TABLE_SCHEMA
1548                              ,qtd.TABLE_NAME
1549                              ,qtd.COLUMN_QTD
1550                              ,ty.TABLE_TYPE
1551                              ,case ty.TABLE_TYPE WHEN 'BASE TABLE' THEN 'TABLE' ELSE ty.TABLE_TYPE end as TABLE_TYPE
1552                        FROM
1553                            (SELECT TABLE_SCHEMA
1554                                  ,TABLE_NAME
1555                                  ,COUNT(TABLE_NAME) COLUMN_QTD
1556                            FROM INFORMATION_SCHEMA.COLUMNS c
1557                            where c.TABLE_SCHEMA <> 'pg_catalog' and c.TABLE_SCHEMA <> 'information_schema'
1558                            group by TABLE_SCHEMA, TABLE_NAME
1559                            ) as qtd
1560                            ,(SELECT TABLE_SCHEMA
1561                                   , TABLE_NAME
1562                                   , TABLE_TYPE
1563                            FROM INFORMATION_SCHEMA.TABLES i
1564                            where I.TABLE_SCHEMA <> 'pg_catalog' and I.TABLE_SCHEMA <> 'information_schema'
1565                            ) as ty
1566                        where qtd.TABLE_SCHEMA = ty.TABLE_SCHEMA
1567                        and qtd.TABLE_NAME = ty.TABLE_NAME
1568                        order by qtd.TABLE_SCHEMA, qtd.TABLE_NAME";
1569                break;
1570            //--------------------------------------------------------------------------------
1571            default:
1572                throw new DomainException('Database '.$DbType.' not implemented ! TDAO->loadTablesFromDatabase. Contribute to the project https://github.com/bjverde/sysgen !');
1573        }
1574        $result = $this->executeSql($sql);
1575        return $result;
1576    }
1577    
1578    private function getMsSqlShema() {
1579        $result = '';
1580        if($this->getSchema()){
1581            $result = " AND upper(c.TABLE_SCHEMA) = upper('".$this->getSchema()."') ";
1582        }
1583        return $result;
1584    }
1585    
1586    public function getSqlToFieldsFromOneStoredProcedureMySQL() {
1587        $sql="select 
1588                     p.parameter_name as COLUMN_NAME
1589                    ,'FALSE' as REQUIRED
1590                    ,r.routine_type AS DATA_TYPE
1591                    ,p.character_maximum_length as CHAR_MAX
1592                    ,p.numeric_precision as NUM_LENGTH
1593                    ,p.numeric_scale as NUM_SCALE
1594                    ,r.ROUTINE_COMMENT as COLUMN_COMMENT
1595                    ,r.specific_name as TABLE_NAME
1596                    ,r.routine_schema as TABLE_SCHEMA
1597                    ,p.ordinal_position
1598                    ,case when p.parameter_mode is null and p.data_type is not null
1599                                then 'RETURN'
1600                                else parameter_mode end as parameter_mode
1601                from information_schema.routines r
1602                left join information_schema.parameters p
1603                          on p.specific_schema = r.routine_schema
1604                          and p.specific_name = r.specific_name
1605                where r.routine_schema not in ('sys', 'information_schema','mysql', 'performance_schema')
1606                and upper(r.specific_name)  = upper('".$this->getTableName()."')
1607                and upper(r.routine_schema) = upper('".$this->getSchema()."')
1608                order by r.routine_schema,
1609                         r.specific_name,
1610                         p.ordinal_position";
1611        return $sql;
1612    }
1613    
1614    public function getSqlToFieldsFromOneStoredProcedureSqlServer() {
1615        $name = $this->getTableName();
1616        $shema = $this->getSchema();
1617        $sql="SELECT REPLACE(P.NAME,'@','')   AS COLUMN_NAME
1618                   ,'FALSE'                   AS REQUIRED
1619                   ,Type_name(P.user_type_id) AS DATA_TYPE
1620                   ,P.max_length              AS CHAR_MAX
1621                   ,null                      AS NUM_LENGTH
1622                   ,null                      AS NUM_SCALE
1623                   ,null                      AS COLUMN_COMMENT
1624                   ,null                      AS COLUMN_COMMENT
1625                   ,null                      AS KEY_TYPE
1626                   ,null                      AS REFERENCED_TABLE_NAME
1627                   ,null                      AS REFERENCED_COLUMN_NAME
1628                   ,Schema_name(schema_id)    AS TABLE_SCHEMA
1629                   ,SO.NAME                   AS table_name
1630            FROM   sys.objects AS SO
1631                   INNER JOIN sys.parameters AS P
1632                           ON SO.object_id = P.object_id
1633            WHERE  SO.object_id IN (SELECT object_id
1634                                    FROM   sys.objects
1635                                    WHERE  type IN ( 'P'))
1636                  AND upper(SO.NAME) = upper('".$name."')
1637                  AND upper(Schema_name(schema_id)) = upper('".$shema."')
1638                  ";
1639        return $sql;
1640    }
1641    
1642    public function getSqlToFieldsOneStoredProcedureFromDatabase() {
1643        //$DbType = $this->getConnDbType();
1644        $DbType = $this->getDbType();
1645        $sql    = null;
1646        $params = null;
1647        $data   = null;
1648        
1649        // ler os campos do banco de dados
1650        if ( $DbType == DBMS_MYSQL ){
1651            $sql   = $this->getSqlToFieldsFromOneStoredProcedureMySQL();
1652        }
1653        else if( $DbType == DBMS_SQLSERVER ) {
1654            $sql   = $this->getSqlToFieldsFromOneStoredProcedureSqlServer();
1655            $params=array($this->getTableName());
1656        }
1657        $result = array();
1658        $result['sql']    = $sql;
1659        $result['params'] = $params;
1660        $result['data']   = $data;        
1661        return $result;
1662    }
1663    
1664    /**
1665     * Recupera as informações dos parametros de uma Storage Procedeure diretamente do banco de dados
1666     * @return null
1667     */
1668    public function loadFieldsOneStoredProcedureFromDatabase() {
1669        $DbType = $this->getDbType();
1670        if ( !$this->getTableName() ) {
1671            throw new InvalidArgumentException('Table Name is empty');
1672        }
1673        $result = $this->getSqlToFieldsOneStoredProcedureFromDatabase();
1674        $sql    = $result['sql'];
1675        switch( $DbType ) {
1676            case DBMS_MYSQL:
1677            case DBMS_SQLSERVER:
1678                $result = $this->executeSql($sql);
1679            break;
1680            //--------------------------------------------------------------------------------
1681            default:
1682                throw new DomainException('Database '.$DbType.' not implemented ! Contribute to the project https://github.com/bjverde/sysgen !');
1683        }
1684        return $result;
1685    }
1686    
1687    public function getSqlToFieldsFromDatabaseMySQL() {
1688        // http://dev.mysql.com/doc/refman/5.0/en/tables-table.html
1689        $sql="SELECT c.column_name COLUMN_NAME
1690                        , case when upper(c.IS_NULLABLE) = 'NO' then 'TRUE' else 'FALSE' end REQUIRED
1691                        , c.data_type DATA_TYPE
1692                        , c.character_maximum_length CHAR_MAX
1693                        , c.numeric_precision NUM_LENGTH
1694                        , c.numeric_scale NUM_SCALE
1695                        , c.COLUMN_COMMENT
1696                        , case when upper(c.COLUMN_KEY) = 'PRI' then 'PK' when ( upper(c.COLUMN_KEY) = 'MUL' AND k.REFERENCED_TABLE_NAME is not null ) then 'FOREIGN KEY' else 0 end  KEY_TYPE
1697                        , case when lower(c.EXTRA) = 'auto_increment' then 1 else 0 end  AUTOINCREMENT
1698                        , c.COLUMN_DEFAULT
1699                        , k.REFERENCED_TABLE_NAME
1700                        , k.REFERENCED_COLUMN_NAME
1701                        , c.TABLE_SCHEMA
1702                        , c.table_name
1703                        , c.TABLE_CATALOG
1704                   from information_schema.columns as c
1705                   left join information_schema.KEY_COLUMN_USAGE as k
1706                   on c.TABLE_SCHEMA = k.TABLE_SCHEMA
1707                   and c.table_name = k.table_name
1708                   and c.column_name = k.column_name
1709                   WHERE upper(c.table_name) = upper('".$this->getTableName()."')
1710                         order by c.table_name
1711                         ,c.ordinal_position";
1712        return $sql;
1713    }
1714    
1715    public function getSqlToFieldsFromDatabaseSqlServer() {
1716        $sql="SELECT c.column_name as COLUMN_NAME
1717                          ,case c.IS_NULLABLE WHEN 'YES' THEN 'FALSE' ELSE 'TRUE' end as REQUIRED
1718                          ,c.DATA_TYPE
1719                          ,c.CHARACTER_MAXIMUM_LENGTH as CHAR_MAX
1720                          ,c.NUMERIC_PRECISION as NUM_LENGTH
1721                          ,c.NUMERIC_SCALE as NUM_SCALE
1722                          ,prop.value AS COLUMN_COMMENT
1723                          ,fk2.CONSTRAINT_TYPE as KEY_TYPE
1724                          ,fk2.REFERENCED_TABLE_NAME
1725                          ,fk2.REFERENCED_COLUMN_NAME
1726                          ,c.TABLE_SCHEMA
1727                          ,c.table_name
1728                          ,c.TABLE_CATALOG
1729                    from INFORMATION_SCHEMA.COLUMNS c
1730                        join sys.columns AS sc on sc.object_id = object_id(c.TABLE_SCHEMA + '.' + c.TABLE_NAME) AND sc.NAME = c.COLUMN_NAME
1731                        LEFT JOIN sys.extended_properties prop ON prop.major_id = sc.object_id AND prop.minor_id = sc.column_id AND prop.NAME = 'MS_Description'
1732                        LEFT JOIN (
1733                            SELECT CT.TABLE_CATALOG
1734                                 , CT.TABLE_SCHEMA
1735                                 , CT.TABLE_NAME
1736                                 , CT.COLUMN_NAME
1737                                 , CT.CONSTRAINT_TYPE
1738                                 , FK.REFERENCED_TABLE_NAME
1739                                 , FK.REFERENCED_COLUMN_NAME
1740                            FROM (
1741                                    SELECT kcu.TABLE_CATALOG
1742                                         , kcu.TABLE_SCHEMA
1743                                         , kcu.TABLE_NAME
1744                                         , kcu.COLUMN_NAME
1745                                         , tc.CONSTRAINT_TYPE
1746                                         , kcu.CONSTRAINT_NAME
1747                                    FROM INFORMATION_SCHEMA.KEY_COLUMN_USAGE kcu
1748                                        ,INFORMATION_SCHEMA.TABLE_CONSTRAINTS  tc
1749                                    where kcu.CONSTRAINT_NAME = tc.CONSTRAINT_NAME
1750                                    ) as CT
1751            
1752                                LEFT JOIN (
1753                                    SELECT
1754                                         KCU1.CONSTRAINT_NAME AS FK_CONSTRAINT_NAME
1755                                        ,KCU1.TABLE_NAME AS FK_TABLE_NAME
1756                                        ,KCU1.COLUMN_NAME AS FK_COLUMN_NAME
1757                                        ,KCU2.TABLE_NAME AS REFERENCED_TABLE_NAME
1758                                        ,KCU2.COLUMN_NAME AS REFERENCED_COLUMN_NAME
1759                                    FROM INFORMATION_SCHEMA.REFERENTIAL_CONSTRAINTS AS RC
1760            
1761                                    INNER JOIN INFORMATION_SCHEMA.KEY_COLUMN_USAGE AS KCU1
1762                                        ON KCU1.CONSTRAINT_CATALOG = RC.CONSTRAINT_CATALOG
1763                                        AND KCU1.CONSTRAINT_SCHEMA = RC.CONSTRAINT_SCHEMA
1764                                        AND KCU1.CONSTRAINT_NAME = RC.CONSTRAINT_NAME
1765            
1766                                    INNER JOIN INFORMATION_SCHEMA.KEY_COLUMN_USAGE AS KCU2
1767                                        ON KCU2.CONSTRAINT_CATALOG = RC.UNIQUE_CONSTRAINT_CATALOG
1768                                        AND KCU2.CONSTRAINT_SCHEMA = RC.UNIQUE_CONSTRAINT_SCHEMA
1769                                        AND KCU2.CONSTRAINT_NAME = RC.UNIQUE_CONSTRAINT_NAME
1770                                        AND KCU2.ORDINAL_POSITION = KCU1.ORDINAL_POSITION
1771                                    ) as FK
1772                            ON CT.CONSTRAINT_NAME = FK.FK_CONSTRAINT_NAME
1773                            AND CT.TABLE_NAME = FK.FK_TABLE_NAME
1774                            AND CT.COLUMN_NAME = FK.FK_COLUMN_NAME
1775                        ) as FK2
1776                        on c.TABLE_SCHEMA = FK2.TABLE_SCHEMA
1777                        and c.TABLE_NAME = Fk2.TABLE_NAME
1778                        and c.COLUMN_NAME = fk2.COLUMN_NAME
1779                    WHERE upper(c.table_name) = upper('".$this->getTableName()."')".$this->getMsSqlShema()."
1780                    ORDER by   c.TABLE_SCHEMA
1781                              ,c.TABLE_NAME
1782                              ,c.ORDINAL_POSITION";
1783        return $sql;
1784    }
1785    
1786    public function getSqlToFieldsFromDatabasePostGres() {
1787        $sql   ="SELECT c.column_name as COLUMN_NAME
1788                      , case c.IS_NULLABLE WHEN 'YES' THEN 'FALSE' ELSE 'TRUE' end as REQUIRED
1789                      , data_type as DATA_TYPE
1790                      , character_maximum_length CHAR_MAX
1791                      , coalesce(numeric_precision, datetime_precision) as NUM_LENGTH
1792                      , numeric_scale as NUM_SCALE
1793                      , des.description COLUMN_COMMENT
1794                      , refe.KEY_TYPE
1795                      , column_default COLUMN_DEFAULT
1796                      , refe.REFERENCED_TABLE_NAME
1797                      , refe.REFERENCED_COLUMN_NAME                      
1798                      , position('nextval(' in column_default)=1 as AUTOINCREMENT
1799                      , c.TABLE_SCHEMA
1800                      , c.table_name
1801                      , c.TABLE_CATALOG
1802                    FROM information_schema.columns as c
1803                         left join (SELECT  st.schemaname as table_schema
1804                                          , st.relname as table_name
1805                                          , pgd.objsubid
1806                                          , pgd.description
1807                                     FROM pg_catalog.pg_statio_all_tables as st
1808                                     inner join pg_catalog.pg_description pgd on (pgd.objoid=st.relid)
1809                                   ) as des
1810                         on (des.objsubid=c.ordinal_position and  des.table_schema = c.table_schema and des.table_name = c.table_name)
1811                         left join (SELECT
1812                                          tc.table_schema
1813                                        , tc.table_name
1814                                        , kcu.column_name
1815                                        , tc.constraint_name    
1816                                        , tc.constraint_type
1817                                        , case when upper(tc.constraint_type) = 'PRIMARY KEY' THEN  'PK' 
1818                                               when upper(tc.constraint_type) = 'FOREIGN KEY' THEN 'FOREIGN KEY' 
1819                                               ELSE tc.constraint_type
1820                                               END  as KEY_TYPE    
1821                                        , ccu.table_schema AS REFERENCED_TABLE_SCHEMA
1822                                        , ccu.table_name AS REFERENCED_TABLE_NAME
1823                                        , ccu.column_name AS REFERENCED_COLUMN_NAME 
1824                                    FROM 
1825                                        information_schema.table_constraints AS tc 
1826                                        JOIN information_schema.key_column_usage AS kcu
1827                                          ON tc.constraint_name = kcu.constraint_name
1828                                        JOIN information_schema.constraint_column_usage AS ccu
1829                                          ON ccu.constraint_name = tc.constraint_name
1830                                    WHERE constraint_type in ('FOREIGN KEY' ,'PRIMARY KEY')
1831                                   ) as refe
1832                         on (refe.table_schema = c.table_schema and refe.table_name = c.table_name and refe.column_name = c.column_name)                         
1833                    WHERE upper(c.table_name) =upper('".$this->getTableName()."')".$this->getMsSqlShema().
1834                    ORDER BY c.TABLE_SCHEMA
1835                            ,c.table_name
1836                            ,c.ordinal_position";
1837        return $sql;
1838    }
1839    
1840    public function getSqlToFieldsFromDatabase() {
1841        //$DbType = $this->getConnDbType();
1842        $DbType = $this->getDbType();
1843        $sql    = null;
1844        $params = null;
1845        $data   = null;
1846        
1847        // ler os campos do banco de dados
1848        if ( $DbType == DBMS_MYSQL ){
1849            $sql   = $this->getSqlToFieldsFromDatabaseMySQL();
1850            $params=null;
1851        }
1852        else if( $DbType == DBMS_SQLSERVER ) {
1853            $sql   = $this->getSqlToFieldsFromDatabaseSqlServer();
1854            $params=array($this->getTableName());
1855        }
1856        else if( $DbType == DBMS_ORACLE ) {
1857            $sql="select a.column_name COLUMN_NAME
1858                    , a.data_type DATA_TYPE
1859                    , data_default as COLUMN_DEFAULT
1860                    , 0 AUTOINCREMENT
1861                    , decode(nullable,'Y',1,0) as REQUIRED
1862                    , a.data_length CHAR_MAX
1863                    , a.data_precision NUM_LENGTH
1864                    , a.data_scale NUM_SCALE
1865                    from all_tab_columns a
1866                    where upper(a.table_name) = upper(:0)";
1867            
1868            $params=array($this->getTableName());
1869        }
1870        else if( $DbType == DBMS_POSTGRES ) {
1871            $schema=( is_null( $this->getSchema() ) ? 'public' : $this->getSchema());
1872            $sql   = $this->getSqlToFieldsFromDatabasePostGres();            
1873            $params=array( $schema ,$this->getTableName() );
1874        }
1875        else if( $DbType == DBMS_FIREBIRD ) {
1876            $sql='SELECT
1877                    RDB$RELATION_FIELDS.RDB$FIELD_NAME COLUMN_NAME,
1878                    \'\' as COLUMN_DEFAULT,
1879                    0 AUTOINCREMENT,
1880                    0 REQUIRED,
1881                    RDB$TYPES.RDB$TYPE_NAME DATA_TYPE,
1882                    RDB$FIELDS.RDB$CHARACTER_LENGTH CHAR_MAX,
1883                    RDB$FIELDS.RDB$FIELD_PRECISION NUM_LENGTH,
1884                    RDB$FIELDS.RDB$FIELD_SCALE NUM_SCALE
1885                    FROM RDB$RELATIONS
1886                    INNER JOIN RDB$RELATION_FIELDS ON RDB$RELATIONS.RDB$RELATION_NAME = RDB$RELATION_FIELDS.RDB$RELATION_NAME
1887                    LEFT JOIN RDB$FIELDS ON RDB$RELATION_FIELDS.RDB$FIELD_SOURCE = RDB$FIELDS.RDB$FIELD_NAME
1888                    LEFT JOIN RDB$TYPES ON RDB$FIELDS.RDB$FIELD_TYPE = RDB$TYPES.RDB$TYPE
1889                    LEFT JOIN RDB$FIELD_DIMENSIONS  on RDB$FIELD_DIMENSIONS.RDB$FIELD_NAME = RDB$FIELDS.RDB$FIELD_NAME
1890                    WHERE UPPER(RDB$RELATIONS.RDB$RELATION_NAME) = upper(?)
1891                    AND RDB$RELATIONS.RDB$SYSTEM_FLAG = 0
1892                    AND RDB$TYPES.RDB$FIELD_NAME=\'RDB$FIELD_TYPE\'
1893                    ORDER BY RDB$RELATION_FIELDS.RDB$FIELD_POSITION';
1894            
1895            $params=array($this->getTableName());
1896        }
1897        else if( $DbType == DBMS_SQLITE) {
1898            $stmt = $this->getConn()->query( "PRAGMA table_info(".$this->getTableName().")");
1899            $res  = $stmt->fetchAll();
1900            $data = null;
1901            $sql  = null;
1902            foreach($res as $rownum => $row)
1903            {
1904                $data[$rownum]['COLUMN_NAME']     = $row['NAME'];
1905                $data[$rownum]['COLUMN_DEFAULT']= $row['DFLT_VALUE'];
1906                $data[$rownum]['AUTOINCREMENT'] = $row['PK'];
1907                $data[$rownum]['REQUIRED']         = ( $row['NOTNULL'] == 0 ? 'FALSE' : 'TRUE' );
1908                $data[$rownum]['DATA_TYPE']     = strtoupper($row['TYPE']);
1909                $data[$rownum]['CHAR_MAX']     = null;
1910                $data[$rownum]['NUM_LENGTH']= 0;
1911                $data[$rownum]['NUM_SCALE']    = 0;
1912                $data[$rownum]['PRIMARYKEY']    = $row['PK'];
1913                if( preg_match('/\(/',$row['TYPE']) == 1 )
1914                {
1915                    $aTemp = explode('(',$row['TYPE']);
1916                    $data[$rownum]['DATA_TYPE'] = $aTemp[0];
1917                    $type= substr($row['TYPE'],strpos($row['TYPE'],'('));
1918                    $type = preg_replace('/(\(|\))/','',$type);
1919                    @list($length,$precision) = explode(',',$type);
1920                    
1921                    if( preg_match('/varchar/i',$aTemp[0]==1) ) {
1922                        $data[$rownum]['DATA_LENGTH'] = $length;
1923                    }
1924                    else {
1925                        $data[$rownum]['CHAR_MAX']       = 0;
1926                        $data[$rownum]['NUM_LENGTH']  = $length;
1927                        $data[$rownum]['NUM_SCALE']   = $precision;
1928                    }
1929                }
1930            }
1931        }
1932        $result = array();
1933        $result['sql']    = $sql;
1934        $result['params'] = $params;
1935        $result['data']   = $data;
1936        
1937        return $result;
1938    }
1939    
1940    /**
1941     * Recupera as informações dos campos da tabela defida na classe diretamente do banco de dados
1942     * @return null
1943     */
1944    public function loadFieldsOneTableFromDatabase() {
1945        $DbType = $this->getDbType();
1946        if ( !$this->getTableName() ) {
1947            throw new InvalidArgumentException('Table Name is empty');
1948        }
1949        $result = $this->getSqlToFieldsFromDatabase();
1950        $sql    = $result['sql'];
1951        $data   = $result['data'];
1952        switch( $DbType ) {
1953            case DBMS_SQLITE:
1954                $result = ArrayHelper::convertArrayPdo2FormDin($data);
1955            break;
1956            //--------------------------------------------------------------------------------
1957            case DBMS_MYSQL:
1958            case DBMS_SQLSERVER:
1959            case DBMS_POSTGRES:
1960                $result = $this->executeSql($sql);
1961            break;
1962            //--------------------------------------------------------------------------------
1963            default:
1964                throw new DomainException('Database '.$DbType.' not implemented ! Contribute to the project https://github.com/bjverde/sysgen !');
1965        }        
1966        return $result;
1967    }
1968
1969    /**
1970    * Recupera as informações dos campos da tabela defida na classe diretamente do banco de dados
1971    * @return null
1972    */
1973    public function loadFieldsFromDatabase() {        
1974        if ( !$this->getTableName() ) {
1975            return null;
1976        }
1977        $result = $this->getSqlToFieldsFromDatabase();
1978        $sql    = $result['sql'];
1979        $params = $result['params'];
1980        $data   = $result['data'];
1981        
1982        if ( !is_null( $sql ) ) {
1983            $data =  $this->query( $sql, $params );
1984        }
1985        
1986        if ( is_array( $data ) ){
1987            foreach( $data as $k => $row ) {
1988                $boolPrimaryKey = ArrayHelper::get($row,'PRIMARYKEY');
1989                $this->addField( trim( $row[ 'COLUMN_NAME' ] )
1990                               , trim( strtolower($row[ 'DATA_TYPE' ]) )
1991                               , ( (int) $row[ 'NUM_LENGTH' ] > 0 ? $row[ 'NUM_LENGTH' ] : $row[ 'CHAR_MAX' ] )
1992                               , $row[ 'NUM_SCALE' ]
1993                               , $row[ 'COLUMN_DEFAULT' ]
1994                               , $row[ 'REQUIRED' ]
1995                               , $row[ 'AUTOINCREMENT' ]
1996                               , $boolPrimaryKey);
1997            }
1998            if ( is_array( $this->getfields() ) ) {
1999                $this->serializeFields();
2000            }
2001        }
2002    }
2003
2004    /**
2005    * Define o nome do campo autoincremento da tabela
2006    *
2007    * @param string $strNewValue
2008    */
2009    public function setAutoincFieldName( $strNewValue = null )
2010    {
2011        $this->autoincFieldName=$strNewValue;
2012    }
2013    /**
2014    * Retorna o nome do campo autoincremento da tabela
2015    *
2016    */
2017    public function getAutoincFieldName()
2018    {
2019        if ( is_null( $this->autoincFieldName ) )
2020        {
2021            if ( $this->getFields() )
2022            {
2023                foreach( $this->getFields()as $fieldName => $objField )
2024                {
2025                    if ( $objField->autoincrement == 1 )
2026                    {
2027                        $this->setAutoincFieldName( $objField->fieldName );
2028                        break;
2029                    }
2030                }
2031            }
2032        }
2033
2034        return trim( $this->autoincFieldName );
2035    }
2036
2037    /**
2038    * Retorna o valor da propriedade lastId
2039    *
2040    * @return integer
2041    */
2042    public function getLastId()
2043    {
2044        return $this->lastId;
2045    }
2046    /**
2047    * Recupera do banco de dados o valor campo autoincremento referente ao último insert ocorrido
2048    *
2049    */
2050    public function getLastInsertId()
2051    {
2052        $sql   =null;
2053        $params=null;
2054        $dbType = $this->getConnDbType();
2055        if ( $dbType == DBMS_MYSQL )
2056        {
2057            $sql = 'SELECT LAST_INSERT_ID() as ID';
2058        }
2059        else if( $dbType == DBMS_POSTGRES )
2060        {
2061            if ( $this->getAutoincFieldName() )
2062            {
2063                $sql="SELECT currval(pg_get_serial_sequence(?,?) ) as ID";
2064
2065                $params=array
2066                    (
2067                    $this->getTableName(),
2068                    $this->getAutoincFieldName()
2069                    );
2070            }
2071        }
2072        else if( $dbType == DBMS_ORACLE )
2073        {
2074            if ( $this->getAutoincFieldName() )
2075            {
2076                return $this->lastId;
2077            }
2078        }
2079        else if( $dbType == DBMS_SQLITE )
2080        {
2081            if ( $this->getAutoincFieldName() )
2082            {
2083                $sql = "select last_insert_rowid() as ID";
2084                $params=null;
2085            }
2086        }
2087        if ( $sql )
2088        {
2089            $res = self::query($sql,$params);
2090            if ( isset( $res[ 0 ][ 'ID' ] ) )
2091            {
2092                return $res[ 0 ][ 'ID' ];
2093            }
2094            else if( isset( $res[ 0 ][ 'id' ] ) )
2095            {
2096                return $res[ 0 ][ 'id' ];
2097            }
2098        }
2099
2100        return null;
2101    }
2102    /**
2103    * Retorna se a conexão está utilizando a extensão PDO para conexão com o
2104    * banco de dados
2105    * Obs: para o banco de dados oracle serão utilizadas as funções oci do php
2106    *
2107    */
2108    public function isPDO()
2109    {
2110        if ( $this->getConn() )
2111        {
2112            return $this->getConn()->isPDO;
2113        }
2114        return null;
2115    }
2116    /**
2117    * Recebe o tipo de dados da coluna e retorna o tipo bind relacionado
2118    *
2119    * @param mixed $strFieldType
2120    */
2121    public function getBindType( $strFieldType = null )
2122    {
2123        $bindTypes[ 'oracle' ][ 'char' ]        =SQLT_CHR;
2124        $bindTypes[ 'oracle' ][ 'varchar' ]     =SQLT_CHR;
2125        $bindTypes[ 'oracle' ][ 'varchar2' ]    =SQLT_CHR;
2126        $bindTypes[ 'oracle' ][ 'integer' ]     =SQLT_INT;
2127        $bindTypes[ 'oracle' ][ 'number' ]      =SQLT_LNG;
2128        $bindTypes[ 'oracle' ][ 'blob' ]        =SQLT_BLOB;
2129        $bindTypes[ 'oracle' ][ 'clob' ]        =SQLT_CLOB;
2130        $bindTypes[ 'oracle' ][ 'long' ]        =SQLT_LNG;
2131        $bindTypes[ 'oracle' ][ 'long raw' ]    =SQLT_LBI;
2132        $bindTypes[ 'oracle' ][ 'date' ]        =SQLT_LNG;
2133        $bindTypes[ 'oracle' ][ 'timestamp(6)' ]=SQLT_LNG;
2134        $strFieldType                           =strtolower( $strFieldType );
2135        $dbType                                 =strtolower( $this->getDbType() );
2136        $result                                 =null;
2137
2138        if ( isset( $bindTypes[ $dbType ][ $strFieldType ] ) )
2139        {
2140            $result = $bindTypes[ $dbType ][ $strFieldType ];
2141        }
2142
2143        return $result;
2144    }
2145    /**
2146    * Ativa / Desativia o commit automático após a execução do método query()
2147    *
2148    * @param boolean $boolNewValue
2149    */
2150    public function setAutoCommit( $boolNewValue = null )
2151    {
2152        $this->autoCommit=$boolNewValue;
2153    }
2154    /**
2155    * Retorna se autocomit está ativo ou não.
2156    *
2157    */
2158    public function getAutoCommit()
2159    {
2160        return ( ( $this->autoCommit === false ) ? false : true );
2161    }
2162    /**
2163    * Inicializa uma transação no banco de dados
2164    *
2165    */
2166    public function beginTransaction()
2167    {
2168        if( $this->getHasActiveTransaction() )
2169        {
2170            return true;
2171        }
2172        if ( $this->getConn() )
2173        {
2174            if ( $this->isPDO() )
2175            {
2176                $this->getConn()->beginTransaction();
2177                $this->hasActiveTransaction=true;
2178                return true;
2179            }
2180        }
2181        return false;
2182    }
2183    /**
2184    * Termina a transação atual e faz com que todas as mudanças sejam permanentes.
2185    *
2186    */
2187    public function commit()
2188    {
2189        if( ! $this->getHasActiveTransaction() )
2190        {
2191            return;
2192        }
2193        $this->hasActiveTransaction=false;
2194        if ( $this->getConn() )
2195        {
2196            if ( $this->getDbType() == DBMS_ORACLE )
2197            {
2198                oci_commit( $this->getConn()->connection );
2199            }
2200            else
2201            {
2202                $this->getConn()->commit();
2203            }
2204        }
2205    }
2206    /**
2207    * Cancela a transação atual desfazendo todas as mudanças pendentes.
2208    *
2209    */
2210    public function rollBack()
2211    {
2212        if( ! $this->getHasActiveTransaction() )
2213        {
2214            return;
2215        }
2216        $this->hasActiveTransaction=false;
2217        if ( $this->getConn() )
2218        {
2219            if ( $this->isPDO() )
2220            {
2221                $this->getConn()->rollBack();
2222            }
2223        }
2224    }
2225    /**
2226    * Define o valor de um campo da tabela
2227    *
2228    * @param string $strFieldName
2229    * @param mixed $value
2230    */
2231    public function setFieldValue($strFieldName,$value=null)
2232    {
2233        $objField = $this->getField($strFieldName);
2234        if( is_object($objField) )
2235        {
2236            $objField->value = $value;
2237        }
2238        else
2239        {
2240            throw new Exception('Invalid field name '.$strFieldName. ' for table '.$this->getTableName() );
2241        }
2242    }
2243    /**
2244    * Retorna o valor de um campo da tabela
2245    *
2246    * @param string $strFieldName
2247    */
2248    public function getFieldValue($strFieldName)
2249    {
2250        $objField = $this->getField($strFieldName);
2251        if( is_object($objField) && isset($objField->value) )
2252        {
2253            return $objField->value;
2254        }
2255        return null;
2256    }
2257    /**
2258    * Define o(s) campo(s) que serão chave primária da tabela
2259    *
2260    * @example
2261    * $daoPg->setPrimaryKey(array('campo1','campo2'));
2262    * $daoPg->setPrimaryKey('campo1,campo2');
2263    *
2264    * @param mixed $mixFieldName
2265    */
2266    public function setPrimaryKey( $mixFieldName=null )
2267    {
2268        $fields     = $this->getFields();
2269        if( is_array( $fields ) )
2270        {
2271            // remover marcação de chave primaria
2272            foreach($fields as $k => $objField )
2273            {
2274                $objField->primaryKey= 0;
2275            }
2276        }
2277        else
2278        {
2279            $this->addField( $mixFieldName );
2280            $fields     = $this->getFields();
2281        }
2282        if( is_string($mixFieldName))
2283        {
2284            if( preg_match('/\,/',$mixFieldName)==1)
2285            {
2286                $mixFieldName = explode(',',$mixFieldName );
2287                $this->setPrimaryKey($mixFieldName);
2288            }
2289            else
2290            {
2291                $mixFieldName = trim($mixFieldName);
2292                $this->primaryKeys[$mixFieldName]=true;
2293                if( $this->getField($mixFieldName) )
2294                {
2295                    $this->getField($mixFieldName)->primaryKey=1;
2296                }
2297            }
2298        }
2299        else if( is_array($mixFieldName))
2300        {
2301            foreach($mixFieldName as $fieldName)
2302            {
2303                $fieldName = trim($fieldName);
2304                $this->primaryKeys[$fieldName]=true;
2305                if( $this->getField($fieldName) )
2306                {
2307                    $this->getField($fieldName)->primaryKey=1;
2308                }
2309            }
2310        }
2311    }
2312    /**
2313    * Retorna o array de campos que fazem parte da chave primária da tabela
2314    *
2315    * @return array
2316    */
2317    public function getPrimaryKeys()
2318    {
2319        $result=array();
2320        if( $this->getFields())
2321        {
2322            foreach($this->getFields() as $fieldName=>$objField)
2323            {
2324                if( isset( $objField->primaryKey) && $objField->primaryKey == 1 )
2325                {
2326                    array_push($result,$objField->fieldName);
2327                }
2328            }
2329        }
2330        else
2331        {
2332            if( is_array($this->primaryKeys) )
2333            {
2334                $result = array_keys($this->primaryKeys);
2335            }
2336        }
2337        return $result;
2338    }
2339    /**
2340    * Persiste os valores dos campos definidos com setFieldValue() chamando
2341    * o método insert ou update
2342    *
2343    */
2344    public function save()
2345    {
2346        $result = false;
2347        $pks = $this->getPrimaryKeys();
2348        if( count($pks) > 0 )
2349        {
2350            $params=null;
2351            $where = array();
2352            foreach($pks as $v)
2353            {
2354                $params[$v] = $this->getFieldValue($v);
2355                if($this->isPDO())
2356                {
2357                    $where[] = $v.'=?';
2358                }
2359                else
2360                {
2361                    $where[] = $v.' = :'.$v;
2362                }
2363            }
2364            $sql = "select ".$pks[0]." from ".$this->getTableName()." where ".implode(' and ',$where);
2365            //print_r($params);
2366            $result = $this->query($sql,$params);
2367            if( is_array($result) && count($result)>0)
2368            {
2369                $result = $this->update();
2370            }
2371            else
2372            {
2373                $result = $this->insert();
2374            }
2375        }
2376        else
2377        {
2378            $result = $this->insert();
2379        }
2380        return $result;
2381    }
2382    /**
2383    * Executa o comando insert com os valores definidos nos campos da tabela
2384    *
2385    */
2386    public function insert()
2387    {
2388        $fields=$this->getFields();
2389        if( is_array( $fields ) )
2390        {
2391            $params=null;
2392            foreach($fields as $fieldName=>$objField)
2393            {
2394                if( ! $objField->autoincrement )
2395                {
2396                    $params[$objField->fieldName] = isset($objField->value) ? $objField->value : null;
2397                }
2398            }
2399        }
2400        return $this->insertValues($params);
2401    }
2402    /**
2403    * Executa o comando update na tabela
2404    *
2405    */
2406    public function update()
2407    {
2408        $fields=$this->getFields();
2409        if( is_array( $fields ) )
2410        {
2411            $params=null;
2412            foreach($fields as $fieldName=>$objField)
2413            {
2414                if( ! $objField->autoincrement )
2415                {
2416                    $params[$objField->fieldName] = isset($objField->value) ? $objField->value : null;
2417                }
2418            }
2419        }
2420        return $this->updateValues($params);
2421    }
2422    /**
2423    * Executa o comando delete na tabela
2424    *
2425    */
2426    public function delete()
2427    {
2428        return $this->deleteValues();
2429    }
2430    /**
2431    * Executa o comando insert baseado no array de campos e valores recebidos
2432    *
2433    * @param mixed $arrFieldValues
2434    */
2435    public function insertValues( $arrFieldValues = null )
2436    {
2437        if ( !$this->connect() )
2438        {
2439            return false;
2440        }
2441
2442        try
2443        {
2444            $userTransation = $this->getHasActiveTransaction();
2445            $this->beginTransaction();
2446            if ( $this->getDbType() != DBMS_ORACLE )
2447            {
2448                $sqlInsert      ="insert into " . $this->getTableName() . ' ';
2449                $valuesClause   =array();
2450                $params         =array();
2451                $returningClause='';
2452
2453                foreach( $arrFieldValues as $fieldName => $fieldValue )
2454                {
2455                    $fieldName = trim( $fieldName );
2456
2457                    if ( !$this->getAutoincFieldName() || strtolower( $fieldName ) != strtolower( $this->getAutoincFieldName() ) )
2458                    {
2459                        if( ! is_null( $fieldValue ) )
2460                        {
2461                            $params[ $fieldName ]=$fieldValue;
2462                            $valuesClause[]      ='?';
2463                        }
2464                    }
2465                }
2466                $columnsClause='(' . implode( ',', array_keys( $params ) ) . ')';
2467                $valuesClause ='values (' . implode( ',', $valuesClause ) . ')';
2468                if ( $this->getDbType() == DBMS_POSTGRES && $this->getAutoincFieldName() )
2469                {
2470                    $returningClause = 'returning ' . $this->getAutoincFieldName();
2471                }
2472                $sqlInsert .= trim( ' ' . $columnsClause . ' ' . $valuesClause . ' ' . $returningClause );
2473                $this->lastId=null;
2474                $result = self::query( $sqlInsert, $params );
2475            }
2476            else
2477            {
2478                // oracle
2479                $sqlInsert   ="insert into " . $this->getTableName() . ' ';
2480                $valuesClause=array();
2481                $params      =array();
2482                $returningFields=array();
2483                $returningInto=array();
2484                $descriptors=null;
2485                foreach( $arrFieldValues as $fieldName => $fieldValue )
2486                {
2487                    $fieldName = strtolower( trim( $fieldName ) );
2488                    $objField  =$this->getField( $fieldName );
2489
2490                    if ( !$this->getAutoincFieldName() || strtolower( $fieldName ) != strtolower( $this->getAutoincFieldName() ) )
2491                    {
2492                        // valor do campo
2493                        $params[ $fieldName ]=$fieldValue;
2494
2495                        // campo blob
2496                        if ( $objField && strtoupper( $objField->fieldType ) == 'BLOB' )
2497                        {
2498                            $valuesClause[]='empty_blob()';
2499                            array_push( $returningFields, $fieldName );
2500                            array_push( $returningInto, ':' . $fieldName );
2501                        }
2502                        else if( $objField && strtoupper( $objField->fieldType ) == 'CLOB' )
2503                        {
2504                            $valuesClause[]='empty_clob()';
2505                            array_push( $returningFields, $fieldName );
2506                            array_push( $returningInto, ':' . $fieldName );
2507                        }
2508                        else
2509                        {
2510                            $valuesClause[] = ':' . $fieldName;
2511                        }
2512                    }
2513                }
2514
2515                $params       =$this->prepareParams( $params, true ); // tratar acentos
2516                $columnsClause='(' . implode( ',', array_keys( $params ) ) . ')';
2517                $valuesClause ='values (' . implode( ',', $valuesClause ) . ')';
2518
2519                if ( $this->getAutoincFieldName() )
2520                {
2521                    array_push( $returningFields, $this->getAutoincFieldName() );
2522                    array_push( $returningInto, ':' . $this->getAutoincFieldName() );
2523                }
2524
2525                $returningClause='';
2526
2527                if ( count( $returningFields ) > 0 )
2528                {
2529                    $returningClause = ' returning ' . implode( ',', $returningFields ) . ' into ' . implode( ',', $returningInto );
2530                }
2531                $sqlInsert .= $columnsClause . ' ' . $valuesClause . ' ' . $returningClause;
2532                $stmt=oci_parse( $this->getConn()->connection, $sqlInsert );
2533                foreach( $params as $fieldName => $fieldValue )
2534                {
2535                    $objField = $this->getField( $fieldName );
2536
2537                    if ( $objField )
2538                    {
2539                        $bindType=$this->getBindType( $objField->fieldType );
2540                        if ( $bindType == SQLT_CLOB )
2541                        {
2542                            $descriptors[ $fieldName ]=$params[ $fieldName ];
2543                            $params[ $fieldName ]     =oci_new_descriptor( $this->getConn()->connection );
2544                            oci_bind_by_name( $stmt, ':' . $fieldName, $params[ $fieldName ], -1, SQLT_CLOB );
2545                        }
2546                        else if( $bindType == SQLT_BLOB )
2547                        {
2548                            $descriptors[ $fieldName ]=$params[ $fieldName ];
2549                            $params[ $fieldName ]     =oci_new_descriptor( $this->getConn()->connection );
2550                            oci_bind_by_name( $stmt, ':' . $fieldName, $params[ $fieldName ], -1, SQLT_BLOB );
2551                        }
2552                        else
2553                        {
2554                            oci_bind_by_name( $stmt, ':' . $fieldName, $params[ $fieldName ], $objField->size, $bindType );
2555                        }
2556                    }
2557                    else
2558                    {
2559                        oci_bind_by_name( $stmt, ':' . $fieldName, $params[ $fieldName ] );
2560                    }
2561                }
2562
2563                $lastId      =null;
2564                $this->lastId=null;
2565
2566                // adicionar o campo autoinc no retorno do insert para capturar o valor gerado
2567                if ( $this->getAutoincFieldName() )
2568                {
2569                    oci_bind_by_name( $stmt, ':' . $this->getAutoincFieldName(), $lastId, 20, SQLT_INT );
2570                }
2571
2572                if ( !@oci_execute( $stmt, OCI_NO_AUTO_COMMIT ) )
2573                {
2574                    $e=oci_error( $stmt );
2575                    oci_free_statement( $stmt );
2576
2577                    throw new Exception( 'Insert error ' . $e[ 'message' ] );
2578                }
2579
2580                // salvar os campos lobs
2581                if ( count( $descriptors ) > 0 )
2582                {
2583                    foreach( $descriptors as $k => $v )
2584                    {
2585                        $params[ $k ]->save( $v );
2586                    }
2587                }
2588
2589                if ( $this->getAutoCommit() && ! $userTransation )
2590                {
2591                    $this->commit();
2592                }
2593
2594                oci_free_statement( $stmt );
2595
2596                if ( $lastId )
2597                {
2598                    $result[ 0 ][ $this->getAutoincFieldName()] = $lastId;
2599                }
2600            }
2601        }
2602        catch( Exception $e )
2603        {
2604            if( ! $userTransation )
2605            {
2606                $this->rollBack();
2607            }
2608            $this->setError( $e->getMessage() );
2609            return false;
2610        }
2611        if( $this->getAutoincFieldName() )
2612        {
2613            if ( isset($result) && is_array($result) )
2614            {
2615                if ( isset( $result[ 0 ][ strtolower( $this->getAutoincFieldName() )] ) )
2616                {
2617                    $this->lastId = $result[ 0 ][ strtolower( $this->getAutoincFieldName() )];
2618                }
2619                else if( isset( $result[ 0 ][ strtoupper( $this->getAutoincFieldName() )] ) )
2620                {
2621                    $this->lastId = $result[ 0 ][ strtoupper( $this->getAutoincFieldName() )];
2622                }
2623            }
2624            else
2625            {
2626                $this->lastId = $this->getLastInsertId();
2627            }
2628            $this->setFieldValue($this->getAutoincFieldName(),$this->lastId);
2629        }
2630
2631        if( ! $userTransation )
2632        {
2633            $this->commit();
2634        }
2635        return true;
2636    }
2637
2638    /**
2639    * Executa o comando delete aseado no array de campos e valores recebidos
2640    * @param mixed $arrFieldValues
2641    */
2642    public function deleteValues($arrFieldValues=null)
2643    {
2644        if ( !$this->connect() )
2645        {
2646            return false;
2647        }
2648        $result = false;
2649        try
2650        {
2651            if ( $this->getDbType() != DBMS_ORACLE )
2652            {
2653                $sqlUpdate         = "delete from " . $this->getTableName();
2654                $params         = null;
2655                if( is_array( $arrFieldValues ) )
2656                {
2657                    foreach( $arrFieldValues as $fieldName => $fieldValue )
2658                    {
2659                        $fieldName = trim( $fieldName );
2660                        $params[ $fieldName ]=$fieldValue;
2661                        $whereClause[] = $fieldName.' = ?';
2662                    }
2663                }
2664                else
2665                {
2666                    $pks = $this->getPrimaryKeys();
2667                    if( count($pks) == 0 )
2668                    {
2669                        $this->setError('Primary key for table '.$this->getTableName().' not defined!');
2670                        return $result;
2671                    }
2672                    else
2673                    {
2674                        $whereClause = null;
2675                           foreach($pks as $k=>$v)
2676                        {
2677                            $whereClause[] = $v.' = ?';
2678                            $params[] = $this->getFieldValue($v);
2679                        }
2680                    }
2681                }
2682                if( is_array($params) && is_array($whereClause) )
2683                {
2684                    $whereClause = implode(' and ',$whereClause);
2685                    $sqlUpdate .= ' where '.$whereClause;
2686                    $result = self::query( $sqlUpdate, $params );
2687                }
2688            }
2689            else
2690            {
2691                  // oracle sem PDO
2692                $sql ="delete from " . $this->getTableName();
2693                $whereClause = array();
2694                $params      =null;
2695                if( is_array($arrFieldValues))
2696                {
2697                    foreach( $arrFieldValues as $fieldName => $fieldValue )
2698                    {
2699                        $params[ $fieldName ]=$fieldValue;
2700                        $whereClause[] = $fieldName.'=:' . $fieldName;
2701                    }
2702                }
2703                else
2704                {
2705                    // where
2706                    $pks = $this->getPrimaryKeys();
2707                    if( count($pks) == 0 )
2708                    {
2709                        $this->setError('Primary key for table '.$this->getTableName().' not defined!');
2710                        return $result;
2711                    }
2712                    else
2713                    {
2714                        $whereClause =null;
2715                        foreach($pks as $v)
2716                        {
2717                            $v = strtolower($v);
2718                            $params[$v] = $this->getFieldValue($v);
2719                            $whereClause[] = $v.' = :'.$v;
2720                        }
2721                    }
2722                }
2723                $whereClause = 'where '.implode(' and ', $whereClause);
2724                $sql .= ' '.$whereClause;
2725                $stmt = oci_parse( $this->getConn()->connection, $sql);
2726                if( !$stmt)
2727                {
2728                    $e = oci_error();
2729                    throw new Exception( 'Parse error ' . $e[ 'message' ] );
2730                }
2731
2732                   $params = $this->prepareParams( $params, true ); // tratar acentos
2733                // fazer o bind dos valores aos parametros
2734
2735                foreach( $params as $fieldName => $fieldValue )
2736                {
2737                    oci_bind_by_name( $stmt, ':' . $fieldName, $params[ $fieldName ] );
2738                }
2739                if ( !@oci_execute( $stmt, OCI_NO_AUTO_COMMIT ) )
2740                {
2741                    $e=oci_error( $stmt );
2742                    oci_free_statement( $stmt );
2743                    throw new Exception( 'Update error ' . $e[ 'message' ] );
2744                }
2745                 if ( $this->getAutoCommit() )
2746                {
2747                    $this->commit();
2748                }
2749                $result = true;
2750                 oci_free_statement( $stmt );
2751            }
2752        }
2753        catch(Exception $e)
2754        {
2755            $this->setError($e->getMessage());
2756            return $result;
2757        }
2758        return $result;
2759    }
2760    /**
2761    * Executa o comando update baseado no array de campos e valores recebidos
2762    *
2763    * @param mixed $arrFieldValues
2764    */
2765    public function updateValues($arrFieldValues=null)
2766    {
2767        if ( !$this->connect() )
2768        {
2769            return false;
2770        }
2771        $result = false;
2772        try
2773        {
2774            $pks = $this->getPrimaryKeys();
2775            if( ! is_array($pks))
2776            {
2777                $this->setError('Primary key for table '.$this->getTableName().' not defined!');
2778                return $result;
2779            }
2780
2781            if ( $this->getDbType() != DBMS_ORACLE )
2782            {
2783                $sqlUpdate         = "update " . $this->getTableName() . ' set ';
2784                $valuesClause   = array();
2785                $params         = array();
2786                foreach( $arrFieldValues as $fieldName => $fieldValue )
2787                {
2788                    $fieldName = trim( $fieldName );
2789                    if ( !$this->getAutoincFieldName() || strtolower( $fieldName ) != strtolower( $this->getAutoincFieldName() ) )
2790                    {
2791                        //if( ! is_null( $fieldValue ) )
2792                        {
2793                            $params[ $fieldName ]=$fieldValue;
2794                            $valuesClause[]      = $fieldName.'=?';
2795                        }
2796                    }
2797                }
2798                $valuesClause = implode( ',', $valuesClause );
2799                // criar a clausula where
2800                $sqlUpdate .= trim( $valuesClause );
2801                if( is_array($pks))
2802                {
2803                    $whereClause = array();
2804                       foreach($pks as $k=>$v)
2805                    {
2806
2807                        $whereClause[] = $v.' = ?';
2808                        $params[] = $this->getFieldValue($v);
2809                    }
2810                    $whereClause = implode(' and ',$whereClause);
2811                    $sqlUpdate .= ' where '.$whereClause;
2812                }
2813                $result = self::query( $sqlUpdate, $params );
2814            }
2815            else
2816            {
2817                  // oracle sem PDO
2818                $sql ="update " . $this->getTableName() . ' set ';
2819                $valuesClause=array();
2820                $params      =array();
2821                $returningFields=array();
2822                $returningInto=array();
2823                $descriptors=null;
2824                foreach( $arrFieldValues as $fieldName => $fieldValue )
2825                {
2826                    $fieldName = strtolower( trim( $fieldName ) );
2827                    $objField  = $this->getField( $fieldName );
2828                    if ( !$this->getAutoincFieldName() || strtolower( $fieldName ) != strtolower( $this->getAutoincFieldName() ) )
2829                    {
2830                        // valor do campo
2831                        $params[ $fieldName ]=$fieldValue;
2832
2833                        // campo blob
2834                        if ( $objField && strtoupper( $objField->fieldType ) == 'BLOB' )
2835                        {
2836                            $valuesClause[]= $fieldName.'=empty_blob()';
2837                            array_push( $returningFields, $fieldName );
2838                            array_push( $returningInto, ':' . $fieldName );
2839                        }
2840                        else if( $objField && strtoupper( $objField->fieldType ) == 'CLOB' )
2841                        {
2842                            $valuesClause[] = $fieldName.'= empty_clob()';
2843                            array_push( $returningFields, $fieldName );
2844                            array_push( $returningInto, ':' . $fieldName );
2845                        }
2846                        else
2847                        {
2848                            $valuesClause[] = $fieldName.'=:' . $fieldName;
2849                        }
2850                    }
2851                }
2852                $valuesClause = implode(',',$valuesClause);
2853                $sql .= ' '.$valuesClause;
2854
2855                // where
2856                $whereClause =array();
2857                foreach($pks as $v)
2858                {
2859                    $v = strtolower($v);
2860                    $params['w_'.$v] = $this->getFieldValue($v);
2861                    $whereClause[] = $v.' = :w_'.$v;
2862                }
2863                $whereClause = 'where '.implode(' and ', $whereClause);
2864                $sql .= ' '.$whereClause;
2865
2866                // returning
2867                $returningClause='';
2868                if ( count( $returningFields ) > 0 )
2869                {
2870                    $returningClause = ' returning ' . implode( ',', $returningFields ) . ' into ' . implode( ',', $returningInto );
2871                }
2872
2873                $sql .= ' '.$returningClause;
2874
2875                $stmt = oci_parse( $this->getConn()->connection, $sql);
2876                if( !$stmt)
2877                {
2878                    $e = oci_error();
2879                    throw new Exception( 'Parse error ' . $e[ 'message' ] );
2880                }
2881
2882                   $params = $this->prepareParams( $params, true ); // tratar acentos
2883                // fazer o bind dos valores aos parametros
2884                foreach( $params as $fieldName => $fieldValue )
2885                {
2886                    $objField = $this->getField( $fieldName );
2887
2888                    if ( $objField )
2889                    {
2890                        $bindType=$this->getBindType( $objField->fieldType );
2891                        if ( $bindType == SQLT_CLOB )
2892                        {
2893                            $descriptors[ $fieldName ]=$params[ $fieldName ];
2894                            $params[ $fieldName ]     =oci_new_descriptor( $this->getConn()->connection );
2895                            oci_bind_by_name( $stmt, ':' . $fieldName, $params[ $fieldName ], -1, SQLT_CLOB );
2896                        }
2897                        else if( $bindType == SQLT_BLOB )
2898                        {
2899                            $descriptors[ $fieldName ]=$params[ $fieldName ];
2900                            $params[ $fieldName ]     =oci_new_descriptor( $this->getConn()->connection );
2901                            oci_bind_by_name( $stmt, ':' . $fieldName, $params[ $fieldName ], -1, SQLT_BLOB );
2902                        }
2903                        else
2904                        {
2905                            oci_bind_by_name( $stmt, ':' . $fieldName, $params[ $fieldName ], $objField->size, $bindType );
2906                        }
2907                    }
2908                    else
2909                    {
2910                        oci_bind_by_name( $stmt, ':' . $fieldName, $params[ $fieldName ] );
2911                    }
2912                }
2913                if ( !@oci_execute( $stmt, OCI_NO_AUTO_COMMIT ) )
2914                {
2915                    $e=oci_error( $stmt );
2916                    oci_free_statement( $stmt );
2917
2918                    throw new Exception( 'Update error ' . $e[ 'message' ] );
2919                }
2920
2921                // salvar os campos lobs
2922                if ( count( $descriptors ) > 0 )
2923                {
2924                    foreach( $descriptors as $k => $v )
2925                    {
2926                        $params[ $k ]->save( $v );
2927                    }
2928                }
2929                 if ( $this->getAutoCommit() )
2930                {
2931                    $this->commit();
2932                }
2933                $result = true;
2934                 oci_free_statement( $stmt );
2935            }
2936        }
2937        catch(Exception $e)
2938        {
2939            $this->setError($e->getMessage());
2940            return $result;
2941        }
2942        return $result;
2943    }
2944    /**
2945    * Retorna se já existe ou não uma transação aberta
2946    *
2947    */
2948    public function getHasActiveTransaction()
2949    {
2950        return $this->hasActiveTransaction;
2951    }
2952    /**
2953    * Retorna o último comando sql executado
2954    *
2955    */
2956    public function getSqlCmd()
2957    {
2958        return $this->sqlCmd;
2959    }
2960    /**
2961    * Retorna os parametros recebidos no ultimo comando sql executado
2962    *
2963    */
2964    public function getSqlParams()
2965    {
2966        return $this->sqlParams;
2967    }
2968
2969    /**
2970    * Método mágico para definir/recuperar os valores dos campos no formato
2971    * setNome_campo(0) e getNome_campo();
2972    * sem a necessidade de criar um método get e set para cada campo
2973    *
2974    * @param mixed $m
2975    * @param mixed $a
2976    */
2977    function __call($m, $a)
2978    {
2979        if( preg_match('/^set/',$m) == 1 )
2980        {
2981            $fieldName = substr($m,3);
2982            if( $fieldName )
2983            {
2984                $this->setFieldValue($fieldName, isset( $a[0] ) ? $a[0]:null );
2985                return;
2986            }
2987        }
2988        else
2989        {
2990            if( preg_match('/^get/',$m) == 1 )
2991            {
2992                $fieldName = substr($m,3);
2993                if( $fieldName )
2994                {
2995                    return $this->getFieldValue($fieldName);
2996                }
2997            }
2998        }
2999        throw new Exception( 'Call to Undefined Method/Class Function '.$m );
3000    }
3001    /**
3002    * Manter compatibilidade com a classe TPDOConnection
3003    * retornando o array no formato $data['COLUNA_TABELA'][LINHA]= VALOR;
3004    *
3005    * @param string $sql
3006    * @param string $params
3007    */
3008    function executeSql($sql=null,$params=null){
3009        $data   = $this->query($sql,$params);
3010        $result = ArrayHelper::convertArrayPdo2FormDin($data);
3011        return $result;
3012    }
3013
3014    function getFieldNames() {
3015        if( is_array($this->getFields() ))
3016        {
3017            $arrNames=array();
3018            foreach( $this->getFields() as $fieldName => $objField ) {
3019                $arrNames[] = $objField->fieldName;
3020            }
3021            return implode(',',$arrNames);
3022        }
3023        return '*';
3024    }
3025    /**
3026    * Consulta com retorno no formato de array da Framework FormDin
3027    *
3028    * @param mixed $sql
3029    * @param mixed $params
3030    * @param mixed $fechMode
3031    */
3032    function qfw($sql=null,$params=null,$fechMode=null) {
3033        $data   = $this->query($sql,$params,$fechMode);
3034        $result = ArrayHelper::convertArrayPdo2FormDin($data);
3035        return $result;
3036    }
3037}
3038?>