israel-nogueira/galaxy-db

ORM simples para PHP e Base de Dados

v1.0.2 2023-12-12 14:26 UTC

This package is auto-updated.

Last update: 2024-10-18 18:41:02 UTC


README

Instalação | Config a base | Snippets | Models | Exemplos de uso
Functions | Crypt | Store Procedures | RAC | Migrations

Classe para controlar a sua base de dados no PHP com facilidade e segurança.

Essa classe dá suporte as seguintes conexões:

mysql pgsql sqlite ibase fbird oracle mssql dblib sqlsrv

Instalação

Instale via composer.

    composer require israel-nogueira/galaxy-db

Acrescente em seu composer.json:

    "scripts": {
        "galaxy": "php vendor/israel-nogueira/galaxy-db/src/galaxy"
    }

GUIA PRÁTICO

CONFIGURANDO A BASE

Você pode configuraros dados de conexão via CLI:

  • type: Sigla do tipo de base (mysql, pgsql etc)
  • user: Usuário da base
  • pass: Senha
  • name: Nome da base
  • host Porta

Caso falte algum ou todos os dados, o prompt irá lhe pedir.

  
   composer run-script galaxy config-connection -- --type= --user= --pass= --name= --host=

Ou criar manualmente um arquivo /.env na raiz do seu projeto e preencha os dados de conexão de sua base:

    #/.env

    DB_HOST=localhost
    DB_PORT=3306
    DB_DATABASE=MyDataBase
    DB_TYPE=mysql
    DB_USERNAME=root
    DB_PASSWORD=
    DB_CHAR=
    DB_FLOW=
    DB_FKEY=

Snippets para VSCode

Depois que você configurou os dados de conexão, poderá criar um snippets da classe.
Sim, essa classe também conta com um script que importa a estrutura da sua base de dados.
E monta um snippets com atalhos.

Para criar ou atualizar seu snippets, basta executar:


    composer run-script galaxy update-snippets

E Pronto, você e seu VSCode estão prontos para trabalhar de maneira rápida e eficaz. GalaxyDB

Alguns atalhos:

select, update, insert ou delete retornam a classe completa de CRUD;

table ou ->table:
Mostra a lista de tabelas disponíveis em sua base de dados;
Se tiver -> retorna a função montada ->table("sua-tabela");
Caso contrario, retorna apenas o nome da tabela

colum ou ->colum:
Se tiver -> retorna a função montada ->colum("sua-tabela");
Caso contrario, retorna apenas o nome da coluna.

Inicialmente ela mostra a lista de tabelas disponíveis em sua base de dados;
E na sequencia a lista de colunas daquela tabela selecionada.

columns ou tables :
Você pode retornar uma lista de tabelas ou colunas de sua base de dados

columns ou tables :
Você pode retornar uma lista de tabelas ou colunas de sua base de dados

E com tempo vamos incrementando a lista de atalhos.

CRIANDO MODELS

Este é o comando para criar suas Models.
Cada palavra é um parametro, por exemplo “usuarios e produtos” no comando:

    composer run-script galaxy new-model usuarios produtos

Isso criará automaticamente os seguinte arquivos:

/app/models/usuariosModel.php
/app/models/produtosModel.php

PADRÃO DAS MODELS

Basta importar o autoload e o namespace da sua Model e utilizar

<?php
    include "vendor\autoload.php";
    use IsraelNogueira\Models\usuariosModel;
?>

A Model é o uso da classe abstrata da classe principal.
Nela serão cadastrados os parâmetros de uso da classe.

<?php
    namespace IsraelNogueira\Models;
    use IsraelNogueira\galaxyDB\galaxyDB;

    class usuariosModel    extends    galaxyDB    {
        //  TABELA PADRÃO 
        protected $table =  'usuarios';
        //  COLUNAS BLOQUEADAS 
        protected $columnsBlocked = [];
        //  COLUNAS PERMITIDAS 
        protected $columnsEnabled = [];
        //  FUNÇÕES MYSQL PROIBIDAS 
        protected $functionsBlocked = [];
        //  FUNÇÕES MYSQL PERMITIDAS 
        protected $functionsEnabled = [];

    }
?>

EXEMPLOS DE USO

Select simples

O exemplo apresenta um SELECT básico com um filtro apenas para usuário com ID=7.

Uma array vazia será retornada caso a consulta não encontre resultados.

<?php
    include "vendor\autoload.php";
    use  App\Models\usuariosModel;

    $users =  new usuariosModel();
    $users->colum('nome');//unitario
    $users->colum('email as mail');// com alias
    $users->colum(['endereco','telefone']); // ou ainda varias de uma vez
    $users->set_where('id=7');
    $users->select();
    $_RESULT = $users->fetch_array(); // retorna um ARRAY

?>

Resultará no seguinte select:

SELECT nome,email as mail,endereco,telefone FROM usuarios WHERE id=7

Select mais completo

<?php
    include "vendor\autoload.php";
    use  App\Models\usuariosModel;

    $users =  new  usuariosModel();
    $users->colum('nome');
    $users->colum('bairro_id');

    $users->join('INNER','bairros',' bairros.id=usuarios.bairro_id')
            ->join('LEFT','cidades',' cidades.id=usuarios.cidade_id'); // TIPO | TABELA | ON
            
    $users->group_by('bairros'); // GROUP BY

    $users->like('nome','%edro%')->like('nome','%ão%');

    $users->order('nome','asc')->order('idade','desc'); // ORDER BY nome ASC, idade DESC

    $users->limit(1,10); // SET LIMIT 1, 10
    $users->where('cidades.id=11');
    $users->distinct(); // ignora os resultados repetidos
    $users->debug(true); // false não retornará erros e falhas. Default:true
    $users->select();

    // $_ARRAY[0]["nome"] | $_ARRAY[1]["nome"] 
    $_ARRAY = $users->fetch_array(); 

    // $_OBJECT[0]->nome | $_OBJECT[1]->nome
    $_OBJECT = $users->fetch_obj();
    
?>

Resultará em uma query assim:

SELECT  DISTINCT  nome,  bairro_id  FROM  usuarios  
INNER  JOIN  bairros  ON  bairros.id  =  usuarios.bairro_id  
LEFT  JOIN  cidades  ON  cidades.id  =  usuarios.cidade_id  
WHERE  (  
        cidades.id  =  11  
        AND  (
            Lower(nome)  LIKE  Lower("%edro%")  OR  Lower(nome)  LIKE  Lower("%ão%") 
        )
    ) GROUP  BY  bairros ORDER BY nome ASC, idade DESC

SUB SELECTS

<?php
    include "vendor\autoload.php";
    use  App\Models\usuariosModel;

    $users =  new  usuariosModel();
    // Puxamos todos usuarios que morem na cidade 11 ( 11=Curitiba )
    // Criamos um sub select e instanciamos como "cidade_11"
    $users->set_where('cidade_id=11');
    $users->setSubQuery('cidade_11');

    // Agora selecionamos com o tableSubQuery() nossa subQuery e damos o alias de "curitiba"
    $users->tableSubQuery('(cidade_11) curitiba');
    $users->set_where('curitiba.solteiros=1');

    // Poderiamos parar poraqui mas se quiser aprofundarmos
    $users->setSubQuery('solteiros'); 
    $users->tableSubQuery('(solteiros) sexo');
    $users->set_where('solteiros.sexo="male"');

    //    Executamos o select puxando os moradores da cidade 11 
    //    e depois filtramos os solteiros
    $users->select('homens_solteiros_curitiba');

    $_ARRAY = $users->fetch_array('homens_solteiros_curitiba'); 

?>

Isso resultará na seguinte query:

SELECT  *  
    FROM  (SELECT  *  
        FROM  (SELECT  *  
                FROM  usuarios
                WHERE  (  cidade_id  =  11  ))  curitiba  
        WHERE  (  curitiba.solteiros  =  1  ))  sexo  
WHERE  (  solteiros.sexo  =  "male"  )

Também podemos aplicar uma subquery a uma coluna:

<?php
    include "vendor\autoload.php";
    use  App\Models\meusUsuario;
    $users =  new  usuariosModel();

    // Aqui apenas trazemos o total de usuarios que moram na cidade 11
    $users->colum('COUNT(1) as total_registro ');
    $users->set_where('cidade_id=11');
    $users->setSubQuery('total_11'); // <----- Cria subquery "total_11"

    $users->colum('user.*');
    $users->columSubQuery('(total_11) AS total_curitibanos'); // Monta coluna com a Subquery
    $users->set_where('total_curitibanos>100');
    $users->prepare_select('homens_solteiros_curitiba');    
    $_ARRAY = $users->fetch_array('homens_solteiros_curitiba'); 

?>
SELECT user.*, (
    SELECT  COUNT(1) AS total_registro FROM users WHERE(cidade_id=11)
)  AS  total_curitibanos  
FROM  users  WHERE  (  total_curitibanos  >  100  )

MULTIPLOS SELECTS

Podemos também executar múltiplos selects em uma só instancia:

<?php
    include "vendor\autoload.php";
    use  App\Models\usuariosModel;

    $users =  new  usuariosModel();
    $users->colum('username');
    $users->colum('email');
    $users->limit(1);
    $users->prepare_select('users_1'); //Guardamos a query
    
    $users->table('financeiro__historico'); // pode setar uma nova tabela
    $users->colum('VALOR');
    $users->limit(1);
    $users->where('PAGADOR="'.$uid.'"');
    $users->prepare_select('valores');//Guardamos a query

    // executamos todas as querys 
    $getInfoBanner->execQuery(function($galaxy){});

    $_ARRAY = $users->fetch_array(); 

?>

Nos resultará no seguinte array:

{
    "users_1":[
                {
                    "username": "username_01",
                    "email": "exemplo@email.com"
                }
            ],
    "valores":[
                {
                    "VALOR": "100.00"
                }
            ]
}

Insert

Podemos inserir dados de algumas formas diferentes:

<?php
    include "vendor\autoload.php";
    use  App\Models\usuariosModel;

    //FORMA SIMPLIFICADA
    $users =  new  usuariosModel();
    $users->coluna1 = 'valor';
    $users->coluna2 = 'valor';
    $users->coluna3 = 'valor';
    $users->insert();

    //Todas as condicionais podem ser aplicadas aqui também
    $users =  new  usuariosModel();
    $users->coluna1 = 'valor';
    $users->coluna2 = 'valor';
    $users->coluna3 = 'valor';
    $users->where('NOW() > "00-00-00 00:00:00"');
    $users->insert();
?>

MULTIPLOS INSERTS + TRANSACTION + ROLLBACK

<?
    // MULTIPLOS INSERTS
    $users =  new  usuariosModel();
    $users->coluna1 = 'valor';
    $users->coluna2 = 'valor';
    $users->coluna3 = 'valor';
    $users->prepare_insert();

    $users->coluna1 = 'valor';
    $users->coluna2 = 'valor';
    $users->coluna3 = 'valor';
    $users->where('NOW() > "00-00-00 00:00:00"');
    $users->prepare_insert();

    // TRANSACTION + ROLLBACK
    $users->transaction(function ($ERROR) {
        throw  new  ErrorException($ERROR, 1); // erro
    });

    //EXECUTA OS INSERTS
    $users->execQuery(function($galaxy){});
?>

INSERT ARRAY + TRANSACTION + ROLLBACK

<?
    //PUXANDO UMA ARRAY
    $users =  new  usuariosModel();
    $users->set_insert_obj(['UID'=>32,'NOME'=>'João', 'IDADE'=>27]);
    $users->prepare_insert();

    //DENTRO DE UM LAÇO
    foreach($_RESULTADO as $OBJ){
        $users->set_insert_obj($OBJ);
        $users->prepare_insert();
    }

    // TRANSACTION + ROLLBACK
    $users->transaction(function ($ERROR) {
        throw  new  ErrorException($ERROR, 1); // erro
    });

    //EXECUTA OS INSERTS
    $users->execQuery(function($galaxy){});
?>

CALLBACKS

Para termos um callback de sucesso ou erro basta inserir:

<?

        $users =	new galaxyDB();
        $users->connect();
        $users->table('usuarios');
        $users->UID = 3456;
        $users->NOME='João';
        $users->IDADE=27;
        $users->prepare_insert('adiciona_user');

        $users->transaction(function ($ERROR) {
            // Callback de erro!
            // Aqui o $ERROR, é o proprio retorno do MySQL
            throw  new  ErrorException($ERROR, 1);
        });

        $users->execQuery(function($galaxy){
            // Callback de sucesso!
            // Aqui o $galaxy, é o proprio objeto da classe
            // que no caso é  $users
            die(var_dump($galaxy->_last_id));
        });


?>

UPDATE:

<?php
    include "vendor\autoload.php";
    use  App\Models\usuariosModel;

    //FORMA SIMPLIFICADA
    $users =  new  usuariosModel();
    $users->coluna1 = 'valor';
    $users->coluna2 = 'valor';
    $users->coluna3 = 'valor';
    $users->update();
    
    //Todas as condicionais podem ser aplicadas aqui também
    $users =  new  usuariosModel();
    $users->coluna1 = 'valor';
    $users->coluna2 = 'valor';
    $users->coluna3 = 'valor';
    $users->where('UID="7365823765"');
    $users->update();
?>

MULTIPLOS UPDATES + TRANSACTION + ROLLBACK:

<?php
    // MULTIPLOS UPDATES
    $users =  new  usuariosModel();
    $users->coluna1 = 'valor';
    $users->coluna2 = 'valor';
    $users->coluna3 = 'valor';
    $users->where('UID="46746876"');
    $users->prepare_update();
    
    $users->coluna1 = 'valor';
    $users->coluna2 = 'valor';
    $users->coluna3 = 'valor';
    $users->where('UID="9653566573"');
    $users->prepare_update();
    
    // TRANSACTION + ROLLBACK
    $users->transaction(function ($ERROR) {
        throw  new  ErrorException($ERROR, 1); // erro
    });
    
    //EXECUTA OS UPDATES
    $users->execQuery(function($galaxy){});
?>

MULTIPLOS UPDATES COM ARRAYS:

<?php
    //PUXANDO UMA ARRAY
    $users =  new  usuariosModel();
    $users->set_update_obj(['UID'=>32,'NOME'=>'João', 'IDADE'=>27]);
    $users->prepare_update();

    //DENTRO DE UM LAÇO
    foreach($_RESULTADO as $OBJ){
        $users->set_update_obj($OBJ);
        $users->prepare_update();
    }

    // TRANSACTION + ROLLBACK
    $users->transaction(function ($ERROR) {
        throw  new  ErrorException($ERROR, 1); // erro
    });

    //EXECUTA OS INSERTS
    $users->execQuery(function($galaxy){});
?>

DELETE

<?php

    //DELETE DIRETO E SIMPLES
    $users =  new  usuariosModel();
    $users->where('UID=32');
    $users->delete();

    //PREPARANDO MULTIPLOS
    $users =  new  usuariosModel();
    $users->where('UID=32');
    $users->prepare_delete();//Armazena

    //DENTRO DE UM LAÇO
    foreach($_RESULTADO as $OBJ){
        $users->where('UID='.$OBJ['UID']);
        $users->prepare_delete();//Armazena
    }

    // TRANSACTION + ROLLBACK
    $users->transaction(function ($ERROR) {
        throw  new  ErrorException($ERROR, 1); // erro
    });

    //EXECUTA OS DELETES
    $users->execQuery(function($galaxy){});
?>

FUNÇÕES NA MODEL

Você pode também estender padrões em sua model.
Podendo abstrair mais nossas consultas.

Seguindo o exemplo abaixo:

<?php
    namespace IsraelNogueira\Models;
    use IsraelNogueira\galaxyDB\galaxyDB;

    class usuariosModel    extends    galaxyDB    {
        protected $table=  'usuarios';

        // AQUI MONTAMOS A NOSSA FUNÇÃO ESTENDIDA
        public function cidadeEstado(){
            $this->colum('city.nome as cidade');
            $this->colum('uf.nome as uf');
            $this->join('LEFT','table_cidade cidade','cidade.id=usuarios.cidade_id');
            $this->join('LEFT','table_uf uf','uf.id=cidade.uf_id');
        }

    }
?>

E quando for utilizar a classe:

<?php
    include "vendor\autoload.php";
    use  App\Models\usuariosModel;

    $users =  new usuariosModel();
    $users->colum('nome');
    $users->colum('idade');
    $users->cidadeEstado(); //====> aqui executamos nossa função
    $users->select();
    $_RESULT = $users->fetch_array();

?>

STORED PROCEDURES

Uma Store Procedure, pode ser chamada de duas maneiras.

1ª - Função ->SP()

$usuarios->sp( NOME_DA_SP, ARRAY_PARAMS );

<?php
    include "vendor\autoload.php";
    use  App\Models\usuariosModel;

    $usuarios = new usuariosModel();
    $usuarios->sp("processaDados",['PARAM0','PARAM1','PARAM2']);
    $usuarios->prepare_sp();
    $usuarios->transaction(function ($ERROR) {
        throw  new  ErrorException($ERROR, 1); // erro
    });
    $usuarios->execQuery(function($galaxy){});

    $_RESULT = $users->fetch_array();


?>

2ª - FUNÇÃO MÁGICA

Você também pode chamar simplesmente adicionando sp_ na frente da sua função, que a classe automaticamente entende que essa função é uma Stored Procedure;

Exemplo:

<?php
    include "vendor\autoload.php";
    use  App\Models\usuariosModel;

    $usuarios = new usuariosModel();
	$teste->sp_processaDados('PARAM0','PARAM1','PARAM2');
	$teste->sp_sobePontos('PARAM0','PARAM1','PARAM2');
	$teste->prepare_sp();

	$teste->transaction(function ($ERROR) {
        throw  new  ErrorException($ERROR, 1); // erro
    });
	$teste->execQuery(function($galaxy){});

?>

PARÂMTROS IN OUT

Todo parâmetro que você inserir com @ no início, a classe identifica que é um parâmetro de saída.

<?php
    include "vendor\autoload.php";
    use  App\Models\usuariosModel;

    $usuarios = new usuariosModel();
	$teste->sp_processaDados('PARAM0','@_NOME','@_EMAIL',25);
	$teste->sp_sobePontos(637,'@_NOME');
	$teste->prepare_sp();

	$teste->transaction(function ($ERROR) {
        throw  new  ErrorException($ERROR, 1); // erro
    });
	$teste->execQuery(function($galaxy){});

	$_RESULT = $teste->params_sp();

?>

A variável $_RESULT representará a seguinte saída:

    {
        "processaDados":{
            "@_NOME":"João da Silva",
            "@_EMAIL":"joao@gmail.com",
        },
        "sobePontos":{
            "@_NOME2":"João da Silva"
        }
    }

PARÂMTROS IN OUT MAIS SELECTS

Caso a sua Store Procedure possúa algum select interno, será processado como uma query;

<?php
    include "vendor\autoload.php";
    use  App\Models\usuariosModel;

    $usuarios = new usuariosModel();
	$usuarios->table("produtos");
	$usuarios->limit(1);
	$usuarios->prepare_select("LISTA_PRODUTOS");

	$usuarios->sp_processaDados('PARAM0','@_NOME','@_EMAIL',25);
	$usuarios->sp_sobePontos(637,'@_NOME');
	$usuarios->prepare_sp();

	$usuarios->transaction(function ($ERROR) {
        throw  new  ErrorException($ERROR, 1); // erro
    });
	$usuarios->execQuery(function($galaxy){});

    $_RESULT = $usuarios->fetch_array();
    $_OUTPUT = $usuarios->params_sp();

?>

Resultará em:

$_RESULT:

    {
        "LISTA_PRODUTOS" : [
                    {
                        "id": 654,
                        "nome": "cadeira de madeira",
                        "valor": 21.5,
                    },
                    {
                        "id": 655,
                        "nome": "Mesa de plástico",
                        "valor": 149.9,
                    }
                ]
    }

$_OUTPUT:

    {
        "processaDados":{
            "@_NOME":"João da Silva",
            "@_EMAIL":"joao@gmail.com",
        },
        "sobePontos":{
            "@_NOME2":"João da Silva"
        }
    }

CRIPTOGRAFIA

Para utilizar essa funcionalidade, será necessário inserir dois parametros no arquivo /.env:
GALAXY_CRYPT_KEY e GALAXY_CRYPT_IV;

    # /var/www/.env

    # Uma chave forte
    GALAXY_CRYPT_KEY=

    # 16 caracteres
    GALAXY_CRYPT_IV=

Para mais detalhes, leia a documentação do PHP:
https://www.php.net/manual/en/function.openssl-encrypt
https://www.php.net/manual/en/function.openssl-decrypt

Digamos que você tenha algum dado sensível em sua base,
e não gostaria de deixar ela solta em meio a outros dados em suas tabelas;

Você poderá utilizar o método isCrypt()

<?php
    include "vendor\autoload.php";
    use  App\Models\usuariosModel;

    $users =  new  usuariosModel();
    $users->NOME                = 'João da Silva';
    $users->isCrypt()->CPF      = '947.029.456-67';
    $users->isCrypt()->EMAIL    = 'email@secret.com';
    $users->isCrypt()->PIN      = '3659';
    $users->insert();

?>

Em sua base ficará assim:

E quando for receber esse valor, sete novamente a flag.

<?php
    include "vendor\autoload.php";
    use  App\Models\usuariosModel;

    $users =  new  usuariosModel();
    $users->colum('NOME');
    $users->isCrypt()->colum('CPF');
    $users->isCrypt()->colum('EMAIL');
    $users->isCrypt()->colum('PIN');

    $users->prepare_select('usuarios');
    $users->transaction(function ($ERROR) {
        throw  new  ErrorException($ERROR, 1); // erro
    });
    $users->execQuery(function($galaxy){});


?>

RAC - REGISTRO DE ALTERAÇÕES DE CONTEÚDO

O GalaxyDB possui um mecanismo integrado de registro de alterações de conteúdo que permite rastrear e visualizar todas as modificações feitas nos dados do conteúdo. Esse recurso permite uma gestão mais eficiente e um histórico completo das alterações realizadas, facilitando a auditoria e o controle de versões.

Para ativar serviço:

$   composer run-script galaxy enable-rac

Para desativar serviço:

$   composer run-script galaxy disable-rac

Você também pode executar programaticamente em PHP:

<?php
    include "vendor\autoload.php";
    use IsraelNogueira\galaxyDB\galaxyDB;

    // ATIVA SERVIÇO
	$_SELECT =	new galaxyDB();
	$_SELECT->connect();
	$_SELECT->enableRAC();

    // DESATIVA SERVIÇO
	$_SELECT =	new galaxyDB();
	$_SELECT->connect();
	$_SELECT->disableRAC();

?>

Isso criará uma tabela em sua base chamada GALAXY__RAC onde será inserido 5 colunas:

  • TABELA: Tabela que foi feita a ação
  • ACTION: INSERT | UPDATE | DELETE
  • QUERY: Query que foi executada
  • ROLLBACK: Query "ctrl+z", voltará ao estado anterior da ação executada
  • DATA_HORA: Data e hora que foi executado o comando

MIGRATIONS

O GalaxyDB também possúi um sistema de migration próprio;
Isso quer dizer que todas as alterações estruturais feitas na base de dados,
como criação/alterações/exclusões de TABELAS,COLUNAS, TRIGGERS ou STORE PROCEDURES.

Atenção:
Para que essas funções funcionem, é necessário antes executar esse comando em seu MySQL;
Obs.: Coloque o PATH do seu arquivo da sua preferencia

    SET GLOBAL general_log = 'ON';
    SET GLOBAL general_log_file="/var/www/html/galaxyDB/galaxy.log";

EXECUTANDO

Pronto! Agora que estamos configurados, você pode criar umas tabelas,
editar umas colunas, criar algumas triggers e execute o comando:

CLI:

  
   composer run-script galaxy new-migration

Você também pode executar programaticamente em PHP:

<?php
    include "vendor\autoload.php";
    use IsraelNogueira\galaxyDB\galaxyDB;

	$_SELECT =	new galaxyDB();
	$_SELECT->connect();
	$_SELECT->setHistorySQLfile();

?>

Agora você poderá verificar que foi criado um arquivo na raiz do sistema:

/galaxyDB/{DB_DATABASE}_{d-m-Y-H-i-s}.sql;

CREATE TABLE `DBNAME`.`NOVA_TABELA` (`ID` INT NOT NULL AUTO_INCREMENT , `COLUNA1` VARCHAR(123) NOT NULL, `COLUNA2` INT(11) NOT NULL , PRIMARY KEY (`ID`)) ENGINE = InnoDB;
ALTER TABLE `NOVA_TABELA` DROP `COLUNA1`;
ALTER TABLE `NOVA_TABELA` DROP `COLUNA2`;