├── .gitignore ├── composer.json ├── readme.md └── src └── TQuery.php /.gitignore: -------------------------------------------------------------------------------- 1 | /vendor/ 2 | -------------------------------------------------------------------------------- /composer.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "jheferson-br/tquery", 3 | "description": "Lib em PHP para execução de arquivos SQL. Uso restrito para projetos Adianti", 4 | "type": "library", 5 | "license": "mit", 6 | "autoload": { 7 | "psr-4": { 8 | "":"src/" 9 | } 10 | }, 11 | "authors": [ 12 | { 13 | "name": "Jheferson Fonseca Gonçalves", 14 | "email": "play_jheferson@hotmail.com" 15 | } 16 | ], 17 | "minimum-stability": "dev", 18 | "require": {} 19 | } 20 | -------------------------------------------------------------------------------- /readme.md: -------------------------------------------------------------------------------- 1 | # TQuery 2 | ## Sobre o Componente 3 | 4 | A classe TQuery foi desenvolvida para trazer para o Adianti framework uma abordagem diferente na montagem e execução das querys. 5 | 6 | Com ela é possível executar arquivos **'.sql'** sendo possível separar as instruções SQL do código PHP. 7 | 8 | Com isso temos uma melhor legibilidade do código SQL. 9 | ## Instalação 10 | 11 | Como se trata de um pacote composer, basta usar o comando: 12 | ```shell 13 | composer require 'jheferson-br/tquery' 14 | ``` 15 | 16 | ## Exemplo de Uso 17 | 18 | Para entendermos melhor como a classe funciona, veja este exemplo simples. 19 | 20 | Suponhamos que precisamos executar a seguinte instrução no banco de dados para limpar as tabelas do sistema: 21 | ```sql 22 | TRUNCATE TABLE cliente; 23 | TRUNCATE TABLE produto; 24 | TRUNCATE TABLE fornecedor; 25 | ``` 26 | Que está salvo na pasta **app/querys/** do projeto, no arquivo **LimpaTabelas.sql**. 27 | 28 | Usando a classe TQuery, ficaria assim: 29 | ```php 30 | TTransaction::open('ERP'); 31 | 32 | // instanciando o objeto TQuery. 33 | $sql = new TQuery("LimpaTabelas.sql"); 34 | //Definindo o local onde os arquivos '.sql' serão encontrados. 35 | $sql->setBasePathQuerys("app/querys/"); 36 | //Definindo um separador de querys para a execução de varios comandos dentro do mesmo arquivo .sql 37 | $sql->setMultiQuerySeparator(";"); 38 | //Executando as querys. 39 | $afected_rows = $sql->execute(); 40 | //Imprimindo na tela a quantidade de linhas que sofreram alterações com a execução da query. 41 | print_r($afected_rows); 42 | ``` 43 | 44 | Note que a classe TQuery precisa de uma transação aberta com o **TTransaction** para ser executada, mantendo o padrão do Adianti Framework. 45 | 46 | Além disso todos os comandos executados com o metodo **execute()** serão logadas no sistema de logs do Adianti. 47 | 48 | A TQuery também é capaz de excutar querys de consultas, como joins complexos. Muitas vezes utilizar uma View como é recomentando para o framework se torna algo oneroso de dar manutenção. 49 | 50 | Pensando nisso foi desenvolvido o metodo **load()** que pode receber um **TCriteria** nativo do framework como parâmetro, mantendo a compatibilidade com o framework. 51 | 52 | Imagine a necessidade de trazer um join complexo como este: 53 | ```sql 54 | SELECT 55 | `mes`.`men_mesano` AS `men_mesano`, 56 | `mes`.`men_insc_muni` AS `men_insc_muni`, 57 | `mes`.`men_conta` AS `men_conta`, 58 | `pla`.`pla_bacen`, 59 | `mes`.`cod_trib_desif` AS `cod_trib_desif`, 60 | SUM(if(COALESCE(`mes`.`men_mes_santer`,0) < 0, 0, COALESCE(`mes`.`men_mes_santer`,0))) AS `sald_inic`, 61 | SUM(COALESCE(`mes`.`men_cred_mes`,0)) AS `men_cred_mes`, 62 | SUM(COALESCE(`mes`.`men_deb_mes`,0)) AS `men_deb_mes`, 63 | SUM(COALESCE(`mes`.`men_tributavel`,0)) AS `men_tributavel`, 64 | SUM(COALESCE(`mes`.`men_deducao`,0)) AS `men_deducao`, 65 | SUM(COALESCE(`mes`.`men_tributavel`,0)) - SUM(`mes`.`men_deducao`) AS `base_calc`, 66 | ( 67 | SUM(COALESCE(`mes`.`men_tributavel`,0)) - SUM(COALESCE(`mes`.`men_deducao`,0)) 68 | ) * COALESCE(`mes`.`men_aliquota`,0) / 100 AS `valr_issqn_retd`, 69 | `mes`.`men_desc_dedu` AS `men_desc_dedu`, 70 | `mes`.`men_aliquota` AS `men_aliquota`, 71 | `mes`.`men_incentivo` AS `men_incentivo`, 72 | `mes`.`men_desc_incen` AS `men_desc_incen`, 73 | `mes`.`men_motivo_nao_exig` AS `men_motivo_nao_exig`, 74 | `mes`.`men_processo_nao_exig` AS `men_processo_nao_exig`, 75 | `mes`.`men_mes_compensacao` AS `men_mes_compensacao`, 76 | `mes`.`men_vlr_compensacao` AS `men_vlr_compensacao`, 77 | `pac`.`cnpj` AS `cnpj` 78 | FROM 79 | ( 80 | des_plano AS pla 81 | LEFT JOIN `des_mensal` AS `mes` 82 | ON (pla.pla_conta = mes.men_conta) 83 | 84 | LEFT JOIN `des_pacs` AS `pac` 85 | ON ( 86 | `mes`.`men_insc_muni` = `pac`.`insc_muni` 87 | ) 88 | ) 89 | {{WHERE}} 90 | 91 | GROUP BY `mes`.`men_mesano`, 92 | `pac`.`insc_muni`, 93 | `mes`.`men_conta`, 94 | `mes`.`men_aliquota` 95 | ``` 96 | 97 | Note que nas condições da query existe um mnemônico denominado **{{WHERE}}**. 98 | Este mnemônico é padrão no **TQuery** e seu objetivo é definir o local onde será incluido as condições **WHERE** da consulta. 99 | 100 | Veja como ficaria o codigo em php: 101 | 102 | ```php 103 | TTransaction::open('ERP'); 104 | 105 | //Definindo os critérios de busca 106 | $criteria = new TCriteria(); 107 | $criteria->add(new TFilter('men_mesano', 'LIKE', "%" . date('Y'))); 108 | 109 | // instanciando o objeto TQuery. 110 | $sql = new TQuery("QryRelatorio.sql"); 111 | //Definindo o local onde os arquivos '.sql' serão encontrados. 112 | $sql->setBasePathQuerys("app/querys/"); 113 | //Executando a query e carregando os objetos 114 | $rows = $sql->load($criteria); 115 | //Imprimindo na tela os resultados da consulta. 116 | print_r($rows); 117 | ``` 118 | Note que a **TQuery** se comporta de forma semelhante a **TRepository** 119 | 120 | Tambem é possível passar parâmetros para as querys usando mnemônicos customizados. 121 | Isso pode ser útil quando queremos enviar um trecho de código SQL para o TQuery incluir na query. 122 | 123 | Veja: 124 | ```sql 125 | SELECT 126 | '12/{{mes_ano}}' AS men_mesano, 127 | '{{men_insc_muni}}' AS men_insc_muni, 128 | pla_conta AS men_conta, 129 | pla.pla_bacen AS pla_bacen, 130 | pla.cod_trib_desif AS cod_trib_desif, 131 | 0 AS sald_inic, 132 | 0 AS men_cred_mes, 133 | 0 AS men_deb_mes, 134 | 0 AS men_tributavel, 135 | 0 AS men_deducao, 136 | 0 AS base_calc, 137 | 0 AS valr_issqn_retd, 138 | 0 AS men_desc_dedu, 139 | aliq.`alq_taxa` AS men_aliquota, 140 | 0 AS men_incentivo, 141 | 0 AS men_desc_incen, 142 | 0 AS men_motivo_nao_exig, 143 | 0 AS men_processo_nao_exig, 144 | 0 AS men_mes_compensacao, 145 | 0 AS men_vlr_compensacao, 146 | '{{cnpj}}' AS cnpj 147 | FROM 148 | des_plano AS pla 149 | LEFT JOIN des_aliquota AS aliq ON aliq.`cid_cod` = (SELECT cid_cod FROM des_coop WHERE coo_cnpj = '{{cnpj}}') AND aliq.`cod_desif` = pla.`cod_trib_desif` 150 | WHERE pla_conta IN 151 | (SELECT 152 | men_conta 153 | FROM 154 | des_mensal as mct 155 | WHERE ( 156 | CAST(CONCAT(SUBSTR(mct.men_mesano, 4,4),SUBSTR(mct.men_mesano, 1,2))AS UNSIGNED INTEGER) 157 | between 158 | CAST(CONCAT(SUBSTR('01/{{mes_ano}}', 4,4),SUBSTR('01/{{mes_ano}}', 1,2))AS UNSIGNED INTEGER) 159 | and CAST(CONCAT(SUBSTR('12/{{mes_ano}}', 4,4),SUBSTR('12/{{mes_ano}}', 1,2))AS UNSIGNED INTEGER) 160 | ) and mct.poa_cod = '{{poa_cod}}') 161 | AND pla_conta LIKE '7%' 162 | and pla.pla_grau = 6 163 | and pla.pla_arquivo = 1 164 | 165 | GROUP BY `men_mesano`, 166 | men_insc_muni, 167 | `men_conta`, 168 | `men_aliquota` 169 | ``` 170 | 171 | Note que a query em questão, possui varios mnemônicos customizados como **{{poa_cod}}** e **{{cnpj}}** 172 | Para enviar para a TQuery os dados para seu mineomonico customizado, basta enviar como segundo parametro no construtor do objeto, um array associativo com as chaves mantendo o mesmo nome do mineomonico. 173 | 174 | Veja um exemplo para a execução da query anterior: 175 | 176 | ```php 177 | TTransaction::open('ERP'); 178 | 179 | //Definindo os critérios de busca 180 | $criteria = new TCriteria(); 181 | $criteria->add(new TFilter('men_mesano', 'LIKE', "%" . date('Y'))); 182 | 183 | //Defininto vetor com mnemônicos customizados 184 | $params = [ 185 | "mes_ano"=> $mes_ano, 186 | "cnpj"=> $PA->cnpj, 187 | "poa_cod"=> $PA->poa_cod, 188 | "men_insc_muni"=> $PA->insc_muni, 189 | ]; 190 | 191 | // instanciando o objeto TQuery informando os parâmtros q serão utilizados. 192 | $sql = new TQuery("QryRelatorio.sql", $params); 193 | //Definindo o local onde os arquivos '.sql' serão encontrados. 194 | $sql->setBasePathQuerys("app/querys/"); 195 | //Executando a query e carregando os objetos 196 | $rows = $sql->load($criteria); 197 | //Imprimindo na tela os resultados da consulta. 198 | print_r($rows); 199 | ``` 200 | Tambem é possível setar os valores dos mnemônicos atraves do método **setParams** quer recebe como parâmetro o vetor com os valores. 201 | Veja como ficaria: 202 | ```php 203 | $sql->setParams($params); 204 | ``` 205 | 206 | # Atenção 207 | #### Nunca use TQuery em telas com inputs de usuários, para a listagem de dados, pois a mesma não possui proteção contra SQL Injection, afinal existe a possibilidade de enviar trechos de códigos para dentro da instrução SQL. 208 | #### A proteção contra SQL Injection só funciona no método load que recebe um TCretéria que por sua vez, ja tem essa proteção. 209 | #### Então tome cuidado ao implementar a TQuery, para não abrir uma falha de segurança no seu sistema. 210 | #### A TQuery é mais indicada para rotinas internas, sem a interferencia dos usuários. 211 | -------------------------------------------------------------------------------- /src/TQuery.php: -------------------------------------------------------------------------------- 1 | query_name = $query_name; 30 | $this->pdo = TTransaction::get(); 31 | $this->obj_expected = $obj; 32 | $this->params = $params; 33 | } 34 | 35 | public function setBasePathQuerys(string $base_path_querys){ 36 | $this->base_path_querys = $base_path_querys; 37 | } 38 | 39 | public function setMultiQuerySeparator($separator = ";") 40 | { 41 | $this->query_separator = $separator; 42 | } 43 | 44 | private function buildQuery() 45 | { 46 | $query = file_get_contents($this->base_path_querys . $this->query_name); 47 | 48 | if ($this->criteria) { 49 | $query = str_replace("{{WHERE}}", " WHERE " . $this->criteria->dump(), $query); 50 | } else { 51 | $query = str_replace("{{WHERE}}", " ", $query); 52 | } 53 | 54 | if ($this->params) { 55 | foreach ($this->params as $name => $value) { 56 | $query = str_replace("{{" . $name . "}}", $value, $query); 57 | } 58 | } 59 | 60 | if (!empty($this->query_separator)) { 61 | $this->querys = explode($this->query_separator, $query); 62 | } else { 63 | $this->query = $query; 64 | } 65 | } 66 | 67 | public function execute() 68 | { 69 | try { 70 | 71 | $this->buildQuery(); 72 | 73 | $totalRows = 0; 74 | 75 | if (is_array($this->querys)){ 76 | foreach ($this->querys as $key => $query) { 77 | if (!empty(trim($query))) { 78 | TTransaction::log($query); 79 | $totalRows += $this->pdo->exec($query); 80 | } 81 | } 82 | } 83 | else{ 84 | TTransaction::log($query); 85 | $totalRows += $this->pdo->exec($this->querys); 86 | } 87 | return $totalRows; 88 | } catch (Exception $e) { 89 | throw new Exception($e->getMessage()); 90 | } 91 | } 92 | 93 | public function load(TCriteria $criteria = null) 94 | { 95 | $data = []; 96 | if ($criteria) { 97 | $this->criteria = $criteria; 98 | } 99 | 100 | $this->buildQuery(); 101 | 102 | if ($this->obj_expected == "stdClass") { 103 | $data = $this->pdo->query($this->query)->fetchAll(PDO::FETCH_OBJ); 104 | } else { 105 | $rows = $this->pdo->query($this->query)->fetchAll(PDO::FETCH_ASSOC); 106 | foreach ($rows as $row) { 107 | $obj = new $this->obj_expected; 108 | $obj->fromArray($row); 109 | $data[] = $obj; 110 | } 111 | } 112 | return $data; 113 | } 114 | 115 | public function dump(TCriteria $criteria = null) 116 | { 117 | $data = []; 118 | if ($criteria) { 119 | $this->criteria = $criteria; 120 | } 121 | 122 | $this->buildQuery(); 123 | 124 | return ($this->querys) ? $this->querys : $this->query; 125 | } 126 | 127 | public function setParams(array $params){ 128 | $this->params = $params; 129 | } 130 | } 131 | --------------------------------------------------------------------------------