i-educar - 1º seminário php no serpro

44
Líder em soluções de TI para governo Sistema de Gestão Escolar Carlos M. dos Santos Coordenação Estratégica de Ações Governamentais - CEAGO 1º Seminário de PHP da SERPRO 9 de novembro de 2015

Upload: flavio-lisboa

Post on 15-Apr-2017

498 views

Category:

Technology


13 download

TRANSCRIPT

Líder em soluções de TI para governo

Sistema de Gestão Escolar

Carlos M. dos SantosCoordenação Estratégica de Ações Governamentais - CEAGO

1º Seminário de PHP da SERPRO9 de novembro de 2015

Agenda

● Introdução

● Histórico

● Situação atual

● Arquitetura de código

● Contribuições do SERPRO

Introdução

● Software de gestão escolar

● Desenvolvido inicialmente pela Prefeitura de Itajaí, SC

● Software Livre

● Desenvolvimento ativo

Software livre

● Portal do Software Público Brasileiro (SPB)

● Disponível sob licença GPL

● http://softwarepublico.gov.br

Histórico

● 2006/2007

● Criação do SoftwareCTIMA – Prefeitura Municipal de Itajaí

● 2008

● Portal do Software Público Brasileiro

● Parceria com Cobra Tecnologia

● 2010/2011

● Comunidade ativa

● Portabilis Tecnologia

● 2014/2015

● Parceria – SERPRO, Ieducativa Soluções e Portabilis Tecnologia

● Trabalho unificado no novo Portal do SPB

Evolução

● CTIMA/Prefeitura de Itajaí

● Desenvolvimento do software

● Cobra Tecnologia

● Refatoração e criação de arquitetura em framework

● Portabilis Tecnologia

● Novas funcionalidades, modelo Software as a Service (SaaS)

● SERPRO

● Migração para PostgreSQL 9.X

● Produção a ser feita em modelo Infrastructure as a Service (IaaS)

● Importação Educacenso

Quem usa?

●Araranguá/SC●Arapiraca/AL●Balneário Arroio do Silva/SC●Balneário Gaivota/SC●Balneário Rincão/SC●Benevides/PA●Bonito/MS●Botucatu/SP●Cocal do Sul/SC●Colégio Tiradentes da Brigada Militar Passo Fundo/RS●Dom Eliseu/PA●Esplanada/BA●Estado de Alagoas●Florianópolis/SC●Grão Pará/SC●Içara/SC●Irecê/BA●Instituto Mãos de Arte Paranoá/DF●Itajaí/SC●Jacinto Machado/SC●Jaguaruna/SC●Lagoa Grande/PE●Laguna/SC●Maracajá/SC●Meleiro/SC

● Montes Claros/MG● Natuba/PB● Nova Veneza/SC● Pacajá/PA● Pescaria Brava/SC● Praia Grande/SC● Polícia Militar da Paraíba● Sangão/SC● Santa Rosa do Sul/SC● São Francisco do

Conde/BA● Sombrio/SC● Timbé do Sul/SC● Sombrio/SC● Valparaíso de Goiás/GO

Programa Cidades Digitais

● Ministério das ComunicaçõesSecretaria de Inclusão Digital

● 362 municípios contemplados

● Infraestrutura de acesso

● Softwares de Gestão Pública

Quem o SERPRO atende?

Valparaíso de GoiásAcordo de Cooperação

Viçosa do CearáPrograma Cidades Digitais

Módulos principais

● Escola

● Cadastros: Controle de alunos, turmas, matrículas, ...

● Movimentações: Controle de notas, frequência, ...

● Documentos: Emissão de boletins, atestados, certificados, …

● Biblioteca

● Controle de empréstimos

● Inventário do acervo

● Transporte escolar

● Cadastro de prestadores e veículos

● Controle de rotas oferecidas

● Agenda

● Gestão de Pessoas

Funcionalidades

● Cadastros

● Funcionários, endereçamento, alunos, escolas, material didático, ...

Funcionalidades

● Operacional

● Matrículas, lançamentos de notas e faltas, calendário letivo, ...

Funcionalidades

● Gerenciamento de biblioteca

● Acervo, controle de empréstimos, ...

Transporte Escolar

Funcionalidades

● Documentos

● Emissão de boletins, relatórios gerenciais e atestados de vaga e matrícula, ...

Benefícios

● Menor despesa com sistemas de informação

● Automação dos procedimentos de gestão escolar

● Redução do uso de papel

● Centralização dos cadastros

● Gestão unificada da rede de ensino

● Frequente evolução do software na comunidade

Demonstração

i-Educar na prática

Arquitetura de código

“Talk is cheap. Show me the code.”Linus Torvalds

Três gerações de código

● 1ª – Gerador de código (ewwww...)

● 2ª – Framework próprio

● 3ª – Migração para API

Exploração arqueológica do código

● Aplicação da intranet da Prefeitura de Itajaí

● Stack em Linux, PostgreSQL (8.2!), PHP e Apache HTTPD

● Diversos sistemas de controle integrados

● Charset ISO-8859-1

Código antigo – DAOs primitivos

<?php

class clsPessoaFisica extends clsPessoaFj { var $idpes; var $data_nasc; var $sexo; var $data_obito; var $nacionalidade; var $idmun_nascimento;

function clsPessoaFisica($int_idpes = FALSE, $numeric_cpf = FALSE, $date_data_nasc = FALSE, $str_sexo = FALSE, …);

function lista($str_nome = FALSE, $numeric_cpf = FALSE, $inicio_limite = FALSE, $qtd_registros = FALSE, $str_orderBy = FALSE, …);

function detalhe();

function excluir();

}

?>

Código antigo – Templates simples

<table summary="" class='tabelanum2' border='0' cellspacing='0' cellpadding='0'>

<tr><td class="r3c1" width='170'><!-- #&MENU&# --></td><td valign=top>

<table summary="" class='tabelanum2' border='0' cellspacing='0' cellpadding='0'>

<tr><td height="0" id="menu_suspenso">

<input type="hidden" value="" id="posx"><input type="hidden" value="" id="posy">

</td></tr><tr>

<td height="100%" valign="top" id="corpo"><!-- #&PROG_ALERT&# --><!-- #&NOTIFICACOES&# --><!-- #&CORPO&# --></td>

</tr></table>

</td></tr>

</table>

Código antigo – Um arquivo .php por página

<?php

class clsIndex extends clsBase {function Formular() {

$this->SetTitulo( "Pessoas Físicas" );$this->processoAp = 43;

$this->addEstilo( "localizacaoSistema" );}

}

class indice extends clsListagem {function Gerar() { /* retorna um monte de HTML em texto */ }

}

$pagina = new clsIndex();

$miolo = new indice();$pagina->addForm( $miolo );

$pagina->MakeAll();

?>

Código antigo – Banco de dados

CREATE TABLE endereco_externo ( idpes numeric(8,0) NOT NULL, tipo numeric(1,0) NOT NULL, idtlog character varying(5) NOT NULL, logradouro character varying(150) NOT NULL, numero numeric(6,0), letra character(1), complemento character varying(20), bairro character varying(40), cep numeric(8,0), cidade character varying(60) NOT NULL, sigla_uf character(2) NOT NULL, reside_desde date, idpes_rev numeric, data_rev timestamp without time zone, origem_gravacao character(1) NOT NULL, idpes_cad numeric, data_cad timestamp without time zone NOT NULL, operacao character(1) NOT NULL, bloco character varying(20), andar numeric(2,0), apartamento numeric(6,0), idsis_rev integer, idsis_cad integer NOT NULL, zona_localizacao integer DEFAULT 1, CONSTRAINT ck_endereco_externo_operacao CHECK ((((operacao = 'I'::bpchar) OR (operacao = 'A'::bpchar)) OR (operacao = 'E'::bpchar))), CONSTRAINT ck_endereco_externo_origem_gravacao CHECK (((((origem_gravacao = 'M'::bpchar) OR (origem_gravacao = 'U'::bpchar)) OR (origem_gravacao = 'C'::bpchar)) OR (origem_gravacao = 'O'::bpchar))), CONSTRAINT ck_endereco_externo_tipo CHECK (((tipo >= (1)::numeric) AND (tipo <= (3)::numeric))));

CREATE TABLE endereco_pessoa ( idpes numeric(8,0) NOT NULL, tipo numeric(1,0) NOT NULL, cep numeric(8,0) NOT NULL, idlog numeric(6,0) NOT NULL, numero numeric(6,0), letra character(1), complemento character varying(20), reside_desde date, idbai numeric(6,0) NOT NULL, idpes_rev numeric, data_rev timestamp without time zone, origem_gravacao character(1) NOT NULL, idpes_cad numeric, data_cad timestamp without time zone NOT NULL, operacao character(1) NOT NULL, bloco character varying(20), andar numeric(2,0), apartamento numeric(6,0), idsis_rev integer, idsis_cad integer NOT NULL, CONSTRAINT ck_endereco_pessoa_operacao CHECK ((((operacao = 'I'::bpchar) OR (operacao = 'A'::bpchar)) OR (operacao = 'E'::bpchar))), CONSTRAINT ck_endereco_pessoa_origem_gravacao CHECK (((((origem_gravacao = 'M'::bpchar) OR (origem_gravacao = 'U'::bpchar)) OR (origem_gravacao = 'C'::bpchar)) OR (origem_gravacao = 'O'::bpchar))), CONSTRAINT ck_endereco_pessoa_tipo CHECK (((tipo >= (1)::numeric) AND (tipo <= (3)::numeric))));

Código antigo – Triggers aleatórias

CREATE FUNCTION fcn_aft_ins_endereco_pessoa() RETURNS trigger LANGUAGE plpgsql AS $$DECLARE v_idpes numeric; v_tipo_endereco text; BEGIN v_idpes := NEW.idpes; v_tipo_endereco := NEW.tipo; EXECUTE 'DELETE FROM cadastro.endereco_externo WHERE idpes='||quote_literal(v_idpes)||' AND tipo='||v_tipo_endereco||';'; RETURN NEW;END; $$;

Código moderno – Framework próprio

~/i/d/i/i/l/CoreExt ls -l master❯❯❯ ⏎

total 140drwxr-xr-x 2 wolverine xmen 4096 Set 25 17:44 Configdrwxr-xr-x 5 wolverine xmen 4096 Ago 6 10:30 Controllerdrwxr-xr-x 2 wolverine xmen 4096 Ago 6 10:30 DataMapperdrwxr-xr-x 2 wolverine xmen 4096 Ago 6 10:30 Entitydrwxr-xr-x 2 wolverine xmen 4096 Ago 6 10:30 Exceptiondrwxr-xr-x 2 wolverine xmen 4096 Ago 6 10:30 Servicedrwxr-xr-x 3 wolverine xmen 4096 Ago 6 10:30 Sessiondrwxr-xr-x 2 wolverine xmen 4096 Ago 6 10:30 Validatedrwxr-xr-x 3 wolverine xmen 4096 Ago 6 10:30 View-rw-r--r-- 1 wolverine xmen 7312 Ago 6 10:30 Config.class.php-rw-r--r-- 1 wolverine xmen 2849 Ago 6 10:30 Configurable.php-rw-r--r-- 1 wolverine xmen 22526 Ago 6 10:30 DataMapper.php-rw-r--r-- 1 wolverine xmen 33495 Ago 6 10:30 Entity.php-rw-r--r-- 1 wolverine xmen 4801 Ago 6 10:30 Enum.php-rw-r--r-- 1 wolverine xmen 1451 Ago 6 10:30 Exception.php-rw-r--r-- 1 wolverine xmen 5437 Ago 6 10:30 Locale.php-rw-r--r-- 1 wolverine xmen 1504 Ago 6 10:30 Session.php-rw-r--r-- 1 wolverine xmen 3205 Ago 6 10:30 Singleton.php-rw-r--r-- 1 wolverine xmen 1486 Ago 6 10:30 View.php

Código moderno – Arquivo de coniguração

[production]app.database.dbname = ieducarapp.database.username = ieducarapp.database.hostname = 10.100.148.56app.database.password = ieducarapp.database.port = 5432

app.aws.bucketname = fotos_alunosapp.aws.awsacesskey = 114aa9bac59642fa951a0fed8359930fc602679dapp.aws.awssecretkey = de53907ec5f10615d1c093bd7eb3d11249381f4f

app.template.vars.instituicao = Secretaria de Educação de Campos Novosapp.template.pdf.titulo = Relatório i-Educarapp.template.pdf.logo = campos_novos.png

app.template.loginpage = templates/template_cidades_digitais.tpl

[gothamcity.ieducar.com.br : production]app.database.dbname = Gothamapp.locale.province = SPapp.entity.name = Prefeitura de Gotham cityreport.logo_file_name = batman.pngapp.routes.redirect_to = /intranet/coringa.php

Código moderno – Bootstrapping

global $coreExt;$coreExt = array();

// Localização para pt_BR$locale = CoreExt_Locale::getInstance();$locale->setCulture('pt_BR')->setLocale();

// Instancia objeto CoreExt_Configuration$coreExt['Config'] = new CoreExt_Config_Ini($configFile, CORE_EXT_CONFIGURATION_ENV);$coreExt['Locale'] = $locale;

// Timezonedate_default_timezone_set($coreExt['Config']->app->locale->timezone);

$tenantEnv = $_SERVER['HTTP_HOST'];

// tenta carregar as configurações da seção especifica do tenant,// ex: ao acessar http://tenant.ieducar.com.br será carregado a seção tenant.ieducar.com.br caso existaif ($coreExt['Config']->hasEnviromentSection($tenantEnv)) $coreExt['Config']->changeEnviroment($tenantEnv);

...

Código moderno – API

class PessoaController extends ApiCoreController { protected function validatesResourceId(); protected function loadPessoa($id = null); protected function loadPessoaByCpf($cpf = null); protected function searchOptions(); protected function get() { $pessoa = array(); if ($this->canGet()) { if ($this->getRequest()->id) $pessoa = $this->loadPessoa($this->getRequest()->id); else $pessoa = $this->loadPessoaByCpf($this->getRequest()->cpf); $attrs = array('id', 'nome'); $pessoa = Portabilis_Array_Utils::filter($pessoa, $attrs); $details = $this->loadDetails($this->getRequest()->id); } return $pessoa; } public function Gerar() { if ($this->isRequestFor('get', 'pessoa-search')) $this->appendResponse($this->search()); elseif ($this->isRequestFor('get', 'pessoa')) $this->appendResponse($this->get()); else $this->notImplementedOperationError(); }}

Código moderno – MVC - View

class ViewController extends Core_Controller_Page_ViewController { protected $_dataMapper = 'Docente_Model_LicenciaturaDataMapper'; protected $_titulo = 'Detalhes da licenciatura'; protected $_processoAp = 635; protected $_tableMap = array( 'Licenciatura' => 'licenciatura', 'Curso' => 'curso', 'Ano de conclusão' => 'anoConclusao', 'IES' => 'ies' ); public function setUrlEditar(CoreExt_Entity $entry) { $this->url_editar = CoreExt_View_Helper_UrlHelper::url( 'edit', array('query' => array( 'id' => $entry->id, 'servidor' => $entry->servidor, 'instituicao' => $this->getRequest()->instituicao )) ); } public function setUrlCancelar(CoreExt_Entity $entry) { $this->url_cancelar = CoreExt_View_Helper_UrlHelper::url( 'index', array('query' => array( 'id' => $entry->id, 'servidor' => $entry->servidor, 'instituicao' => $this->getRequest()->instituicao )) ); }}

Código moderno – MVC - Model

class Docente_Model_Licenciatura extends CoreExt_Entity { protected $_data = array( 'servidor' => NULL, 'licenciatura' => NULL, 'curso' => NULL, 'anoConclusao' => NULL, 'ies' => NULL, 'user' => NULL, 'created_at' => NULL, 'updated_at' => NULL ); protected $_references = array( 'licenciatura' => array( 'value' => NULL, 'class' => 'App_Model_SimNao', 'file' => 'App/Model/SimNao.php' ), 'ies' => array( 'value' => NULL, 'class' => 'Educacenso_Model_IesDataMapper', 'file' => 'Educacenso/Model/IesDataMapper.php' ), 'curso' => array( 'value' => NULL, 'class' => 'Educacenso_Model_CursoSuperiorDataMapper', 'file' => 'Educacenso/Model/CursoSuperiorDataMapper.php' ) );}

Código moderno – Relatórios – Formulários

class BoletimController extends Portabilis_Controller_ReportCoreController { protected $_titulo = 'Boletim Escolar';

function form() { $this->inputsHelper()->dynamic(array('ano', 'instituicao', 'escola', 'curso', 'serie', 'turma')); $this->inputsHelper()->dynamic('matricula', array('required' => false)); $this->inputsHelper()->checkbox('manual', array('label' => 'Preenchimento manual?')); $this->loadResourceAssets($this->getDispatcher()); } function report() {

return new BoletimReport();}

function beforeValidation() { $this->report->addArg('ano', (int)$this->getRequest()->ano); $this->report->addArg('instituicao', (int)$this->getRequest()->ref_cod_instituicao); $this->report->addArg('escola', (int)$this->getRequest()->ref_cod_escola); $this->report->addArg('curso', (int)$this->getRequest()->ref_cod_curso); $this->report->addArg('serie', (int)$this->getRequest()->ref_cod_serie); $this->report->addArg('turma', (int)$this->getRequest()->ref_cod_turma); if (is_null($this->getRequest()->ref_cod_matricula)) $this->report->addArg('matricula',0); else $this->report->addArg('matricula', (int)$this->getRequest()->ref_cod_matricula); $this->report->addArg('manual', $this->getRequest()->manual ? 1 : 0);}}

Código moderno – Relatórios – Mapeamento

class BoletimReport extends Portabilis_Report_ReportCore { function templateName() { $flagTipoBoletimTurma = App_Model_IedFinder::getTurma($codTurma = $this->args['turma']); $flagTipoBoletimTurma = $flagTipoBoletimTurma['tipo_boletim']; if (empty($flagTipoBoletimTurma)) { throw new Exception( Portabilis_String_Utils::toLatin1("Não foi definido o tipo de boletim no cadastro de turmas.") ); } $tiposBoletim = Portabilis_Model_Report_TipoBoletim; $templates = array($tiposBoletim::BIMESTRAL => 'portabilis_boletim', $tiposBoletim::TRIMESTRAL => 'portabilis_boletim_trimestral'); $template = is_null($flagTipoBoletimTurma) ? '' : $templates[$flagTipoBoletimTurma];

function requiredArgs() {$this->addRequiredArg('ano');$this->addRequiredArg('instituicao');$this->addRequiredArg('escola');$this->addRequiredArg('curso');$this->addRequiredArg('serie');$this->addRequiredArg('turma');

}}

Código moderno – Relatórios – .jrxml

<?xml version="1.0" encoding="UTF-8"?><jasperReport xmlns="http://jasperreports.sourceforge.net/jasperreports" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://jasperreports.sourceforge.net/jasperreports http://jasperreports.sourceforge.net/xsd/jasperreport.xsd" name="portabilis_boletim" language="groovy" pageWidth="595" pageHeight="842" columnWidth="555" leftMargin="20" rightMargin="20" topMargin="20" bottomMargin="20" uuid="4f9ea369-c6c3-48c5-ae82-2872022857d3">

<parameter name="ano" class="java.lang.Integer"><defaultValueExpression><![CDATA[new

java.lang.Integer(0)]]></defaultValueExpression></parameter><parameter name="instituicao" class="java.lang.Integer">

<defaultValueExpression><![CDATA[new java.lang.Integer(0)]]></defaultValueExpression>

</parameter><parameter name="escola" class="java.lang.Integer">

<defaultValueExpression><![CDATA[new java.lang.Integer(0)]]></defaultValueExpression>

</parameter><parameter name="curso" class="java.lang.Integer">

<defaultValueExpression><![CDATA[new java.lang.Integer(0)]]></defaultValueExpression>

</parameter><parameter name="serie" class="java.lang.Integer">

<defaultValueExpression><![CDATA[new java.lang.Integer(0)]]></defaultValueExpression>

</parameter>

Futuro para o código

● Premissa: Aprender com o passado

● Merging nos repositórios do SPB

● Migrations: Phinx

● Concluir implementação da API

● Padronizar uma API

● Criar novos clientes – Professor, Gestão, Pais

● Refatorar o backend

Trabalho em Comunidade

Novos documentos e relatórios

Diário de classe

Certificado de conclusão

Atestado de reserva de vaga

...

Administração no atendimento multi-tenant

Múltiplos clientes por

instância de aplicação

Facilidade de administração

Melhorias no acesso ao PostgreSQL

Migração da versão 8.2 para 9.x

Visualização dos dados do coletor de estatísticas

Automação de testes com Behat + Mink

BDD: Behavior-Driven Development

Próximo passo: Integração contínua

Integração com Educacenso

Importação dos dados do Censo Escolar/INEP

Migração completa em desenvolvimento na comunidade

Próximos passos

Conclusão dos rollouts atuais

- Cidades Digitais

- Valparaíso de Goiás

Entrega do modelo de negócio/serviço

Novas funcionalidades e melhoria contínua

"Fazer do SERPRO uma empresa atuante,

parceira e inovadora em soluções de

gestão educacional, escolar e acadêmica

para uma Pátria, de fato, Educadora."

"O SERPRO, em atendimento ao Programa Cidades Digitais,

internalizou o i-Educar e agora implanta uma nova linha de

atuação para atendimento educacional, com

desenvolvimento colaborativo em comunidade."

Carlos M. dos Santos

Desenvolvedor de Software

SERPRO Florianópolis

[email protected]

+55 48 3231 8970