Scriptcaser

Desenvolvendo uma API RESTful no Scriptcase

O scriptcase é um ótimo framework, confesso que não conseguiria desenvolver sistemas funcionais em tão pouco tempo sem ele.

No entanto, à medida que as aplicações web vão evoluindo você também quer que seus projetos no scriptcase tenham o mesmo grau de fluidez, responsividade que projetos desenvolvidos em outros frameworks, como react e angular.

E uma dessas funcionalidades é a incorporação de uma API REST, que são nativas em outros frameworks (ou se não nativas mas de fácil implementação) mas não no scriptcase.

Sentindo essa necessidade de ter uma API REST nos meus projetos para realizar async calls, desenvolvi a minha própria voltada para o scriptcase.

A primeira coisa que iremos fazer é criar uma biblioteca externa chamada API para o projeto.

Ao final da construção de sua API, a estrutura de pastas ficará parecida com a minha estrutura.

A primeira pasta que iremos criar é a config, onde ficarão armazenados os dados de conexão com banco de dados e a classe Conexão.php

Iremos criar a classe Conexão.php, usando o padrão de projeto chamado Singleton, que garante a existência de uma única instância da classe Conexão, mantendo um ponto global de acesso ao objeto.

<?php
	define("MYSQL_HOST", "host");
	define("MYSQL_DB", "nome_do_banco");
	define("MYSQL_USER", "usuario_do_banco");
	define("MYSQL_PASS", "senha_do_banco");

	class Conexao {
	    public static $instance;

	    private function __construct() {
	        //
	    }

	    public static function getInstance() {
	        if (!isset(self::$instance)) {
	            self::$instance = new PDO('mysql:host='.MYSQL_HOST.';dbname='.MYSQL_DB, MYSQL_USER, MYSQL_PASS, array(PDO::MYSQL_ATTR_INIT_COMMAND => "SET NAMES utf8"));
	            self::$instance->setAttribute(PDO::ATTR_ERRMODE, PDO::ERRMODE_EXCEPTION);
	        }

	        return self::$instance;
	    }
	}
?>

As variáveis globais de conexão com o banco podem ficar em outro arquivo, bastando dar um include dentro da classe para usá-las, ou ficar no mesmo arquivo igual no exemplo acima.

O próximo passo é criar a pasta objects, que ficarão os nossos models, tomemos como exemplo o model pessoa.

<?php
class Pessoa {
	
	// attributes
	public $Id;
	public $Matricula;
	public $DataAdmissao;
	public $TempoPosse;
	public $Nome;
	public $Sexo;
	public $Cpf;
	public $Rg;
	public $DataNascimento;
	public $Idade;
	public $EstadoCivil;
	public $Naturalidade;
	public $Celular;
	public $CelularAux;
	public $Email;
	public $Secretaria;
	public $Lotacao;
	public $Cargo;
	public $Foto;
	public $Logradouro;
	public $Bairro;
	public $Cep;
	public $Ativo;
	public $Contribuicao;
	public $DataFiliacao;
	public $TempoFiliacao;
	public $DataDesfiliacao;
	public $Insert;
	public $Update;
	
	// photo attributes
	public $PhotoName;
	public $PhotoType;
	public $PhotoContent;
	public $PhotoPath;
	
	public function photoUpload() {
			
		if(file_put_contents($this->PhotoPath, $this->PhotoContent)) {

			$query = "call sp_save_pessoa_photo_name(?, ?)";

			// prepare query statement
			$stmt = Conexao::getInstance()->prepare($query);
			$stmt->bindParam(1, $this->Id);
			$stmt->bindParam(2, $this->PhotoName);

			// execute query
			$stmt->execute();
			return true;
		}

		return false;
	}
	
	public function autocomplete() {
		$query = "SELECT id, nome, foto FROM v_pessoa";
		
		// prepare query statement
		$stmt = Conexao::getInstance()->prepare($query);

		// execute query
		$stmt->execute();

		return $stmt;
	}
	
	public function readOneMobile() {
		$query = "call sp_get_pessoa_mobile(?)";
		
		// prepare query statement
		$stmt = Conexao::getInstance()->prepare($query);
    	$stmt->bindParam(1, $this->Id);

		// execute query
		$stmt->execute();
		
		// get retrieved row
		$row = $stmt->fetch(PDO::FETCH_ASSOC);

		if($row) {
			// set values to object properties
			$this->Matricula = $row['matricula'];
			$this->Nome = $row['nome'];
			$this->DataAdmissao = $row['data_admissao'];
			$this->Sexo = $row['sexo'];
			$this->DataNascimento = $row['data_nascimento'];
			$this->Secretaria = $row['secretaria'];
			$this->Lotacao = $row['unidade_lotacao'];
			$this->Cargo = $row['cargo'];
			$this->Ativo = $row['ativo'];
			$this->DataFiliacao = $row['data_filiacao'];
			$this->DataDesfiliacao = $row['data_desfiliacao'];
			$this->Email = $row['email'];
			$this->Celular = $row['celular'];
			$this->Foto = $row['foto'];
		}
	}
	
	public function readOne() {
		$query = "call sp_get_pessoa(?)";
		
		// prepare query statement
		$stmt = Conexao::getInstance()->prepare($query);
    	$stmt->bindParam(1, $this->Id);

		// execute query
		$stmt->execute();
		
		// get retrieved row
		$row = $stmt->fetch(PDO::FETCH_ASSOC);

		if($row) {
			// set values to object properties
			$this->Matricula = $row['matricula'];
			$this->Nome = $row['nome'];
			$this->DataAdmissao = $row['data_admissao'];
			$this->Sexo = $row['sexo'];
			$this->DataNascimento = $row['data_nascimento'];
			$this->Secretaria = $row['secretaria'];
			$this->Lotacao = $row['unidade_lotacao'];
			$this->Cargo = $row['cargo'];
			$this->Ativo = $row['ativo'];
			$this->DataFiliacao = $row['data_filiacao'];
			$this->DataDesfiliacao = $row['data_desfiliacao'];
			$this->Email = $row['email'];
			$this->Celular = $row['celular'];
			$this->Foto = $row['foto'];
		}
	}
	
	public function aniversarianteDia() {
		$query = "SELECT id, 
						 matricula, 
						 nome,
						 idade,
						 tempo_filiacao,
						 celular,
						 email,
						 cargo,
						 foto
					FROM 
						v_pessoa_aniversariante_dia";
		
		// prepare query statement
		$stmt = Conexao::getInstance()->prepare($query);

		// execute query
		$stmt->execute();

		return $stmt;
	}
	
	public function counters() {
		$query = "SELECT this_year_count,
						 this_month_count,
						 all_count
					FROM 
						v_pessoa_counter";
		
		// prepare query statement
		$stmt = Conexao::getInstance()->prepare($query);

		// execute query
		$stmt->execute();

		return $stmt;
	}
}

Como você pode ver, teremos que fazer o que scriptcase já faz, ou seja, teremos que criar todo o CRUD para as tabelas que iremos manipular. No meu caso, me baseei no MVC para criar a estrutura.

Se por um lado é ruim, já que dá trabalho, por outro é bom, já que dá ao desenvolvedor maior controle na manipulação das tabelas do banco de dados.

Para exemplificar, usarei o controller aniversariantedia.php construído para o método da model Pessoa.

<?php
// required headers
header("Access-Control-Allow-Origin: *");
header("Content-Type: application/json; charset=UTF-8");
 
// include database and object files
include_once __DIR__ . '/../config/Conexao.php';
include_once __DIR__ . '/../objects/Pessoa.php';
include_once __DIR__ . '/../shared/Utilities.php';

// initialize object
$obj = new Pessoa();

// query products
$stmt = $obj->aniversarianteDia();
$num = $stmt->rowCount();
 
// check if more than 0 record found
if($num > 0) {
	
    // obj array
    $_arr = array();
 
    while ($row = $stmt->fetch(PDO::FETCH_ASSOC)) {
        // extract row
        // this will make $row['name'] to
        // just $name only
        //$row['encoded'] = array_map('utf8_encode', $row);
		
        extract($row);
		 
        $_item=array(
            "id" 			=> $id,
			"matricula"		=> $matricula,
			"nome"			=> $nome,
			"idade"			=> $idade,
			"filiacao"		=> $tempo_filiacao,
			"celular"		=> $celular,
			"email"			=> $email,
			"cargo"			=> $cargo,
			"foto"			=> substr(Utilities::getConfig('geral_baseurl'), 0, -1) . Utilities::getConfig('path_urlfotopessoa') . $foto
            
        );
		
        array_push($_arr, $_item);
    }
	
    // set response code - 200 OK
    http_response_code(200);
	
    echo json_encode($_arr);
}
 
else {
	
    // set response code - 404 Not found
    http_response_code(404);
	
    echo json_encode(
        array("message" => utf8_encode("Nenhum resultado encontrado."))
    );
}
?>

Esse script cria um objeto do tipo pessoa, executa o método aniversarianteDia e retorna os dados em forma de um array json quando chamado.

Para chamar a API dentro da aplicação é necessário ter conhecimento de javascript. Darei um exemplo de como fazer uma chamada utilizando a função fetch do javascript.

<script type="text/javascript">
(function() {
			
    // element lists
    const aniversariantes = document.querySelector('#aniversariantes');
    const atendimentos = document.querySelector('#atendimentos');
    const urls = [{url: '<?php echo sc_url_library("prj", "api", "pessoa/aniversariantedia.php"); ?>', method: renderBirthdayRow}, {url: '<?php echo sc_url_library("prj", "api", "pessoa/counters.php"); ?>', method: renderAssociatesCounters}, {url: '<?php echo sc_url_library("prj", "api", "agenda/day.php"); ?>', method: renderAppointmentRow}, {url: '<?php echo sc_url_library("prj", "api", "agenda/counters.php"); ?>', method: renderAppointmentCounters}, {url: '<?php echo sc_url_library("prj", "api", "carteira/counters.php"); ?>', method: renderWalletCounters}, {url: '<?php echo sc_url_library("prj", "api", "processo/counters.php"); ?>', method: renderLawsuitsCounters}];
			
    urls.map(n => getList(n.url)
        .then(data => data.map(n.method))
	.catch(function(error) {
            console.log(error);
	})
    );
})();
		
function renderAssociatesCounters(row) {
    document.querySelector('#asc_this_year').innerHTML = row.this_year_count;
    document.querySelector('#asc_all').innerHTML = row.all_count;
}
		
function renderWalletCounters(row) {
    document.querySelector('#wlt_this_year').innerHTML = row.this_year_count;
    document.querySelector('#wlt_all').innerHTML = row.all_count;
}
		
function renderLawsuitsCounters(row) {
    document.querySelector('#lst_this_year').innerHTML = row.this_year_count;
    document.querySelector('#lst_all').innerHTML = row.all_count;
}
		
function renderAppointmentCounters(row) {
    document.querySelector('#apt_this_year').innerHTML = row.this_year_count;
    document.querySelector('#apt_all').innerHTML = row.all_count;
}
		
function getList(url) {
    return fetch(url).then(res => res.json());
}
		
function renderBirthdayRow(row) {
    let li = '<li class="collection-item"><div class="row"><div class="col s6"><p class="collections-title">' + row.nome + '</p><p class="collections-content">' + row.cargo + '</p></div><div class="col s2"><span class="task-cat cyan">' + row.idade + ' anos</span></div><div class="col s2"><p class="collections-title">Filiado há</p><p class="collections-content">' + row.filiacao + ' anos</p></div><div class="col s1"><a class="btn-floating btn waves-effect waves-light teal accent-4"><i class="material-icons" title="Enviar E-mail">email</i></a></div><div class="col s1"><a class="btn-floating btn waves-effect waves-light deep-orange accent-2"><i class="material-icons" title="Enviar SMS">sms</i></a></div></div></li>';
    aniversariantes.insertAdjacentHTML('beforeend', li);
}

function renderAppointmentRow(row) {
    let li = '<li class="collection-item"><div class="row"><div class="col s6"><p class="collections-title">' + row.pessoa_nome + '</p><p class="collections-content">' + row.pessoa_cargo + '</p></div><div class="col s2"><span class="task-cat red accent-2">' + row.servico + '</span></div><div class="col s3"><p class="collections-title">Agendado</p><p class="collections-content">' + row.hora_inicio + ' – ' + row.hora_fim + '</p></div><div class="col s1"><a class="btn-floating btn waves-effect waves-light teal accent-4"><i class="material-icons" title="Detalhes">add</i></a></div></div></div></li>';
    atendimentos.insertAdjacentHTML('beforeend', li);
}
</script>

O objetivo desse código é (entre outras coisas) obter a relação de aniversariantes do dia através da função fetch e renderizar em uma tabela, um aniversariante por linha.

Gostou? Então comente, se inscreva na minha newsletter e saiba assim que novos posts saírem do forno.

scriptcaser

9 comments

Newsletter

Se inscreva na nossa newsletter
Se increva hoje na nossa lista de e-mail para receber atualizações, tutoriais e ofertas especiais!

Respeitarei sua privacidade. Seu e-mail nunca será compartilhado.