<?php
namespace App\Controller\Customs;
use App\Helper\DateHelper;
use App\Repository\Painel\VisaoRepository;
use ErrorException;
use Knp\Bundle\PaginatorBundle\Pagination\SlidingPagination;
use Knp\Component\Pager\PaginatorInterface;
use Symfony\Bundle\FrameworkBundle\Controller\AbstractController;
use Symfony\Component\HttpFoundation\RedirectResponse;
use Symfony\Component\HttpFoundation\Request;
use Symfony\Component\HttpFoundation\Response;
use Symfony\Component\Routing\RouterInterface;
use Symfony\Component\Serializer\Encoder\JsonEncoder;
use Symfony\Component\Serializer\Normalizer\ObjectNormalizer;
use Symfony\Component\Serializer\Serializer;
use Symfony\Component\Validator\Validator\ValidatorInterface;
use Twig\Error\RuntimeError;
/**
* Controller para agrupar metodos comuns de execucao nas controllers.
*
* @author Vrunobieira <bruno.vieira@2im.com.br>
* @copyright (c) 2IM Inteligencia Medica <https://www.2im.com.br>
*/
class Custom2IMController extends AbstractController
{
const PERIODO_UNICO_PARA_MULTIPLO = 'PERIODO_UNICO_PARA_MULTIPLO';
const PERIODO_MULTIPLO_PARA_UNICO = 'PERIODO_MULTIPLO_PARA_UNICO';
const TEMPLATEBASE = '';
/**
* @var ValidatorInterface
*/
private $validator;
/**
* @param ValidatorInterface $validator
*/
public function __construct(ValidatorInterface $validator)
{
$this->validator = $validator;
}
/**
* Iguala o período inicial ao final caso o filtro seja por mês ou ano.
*/
public function trataPeriodoMultiploParaUnico()
{
$request = new Request();
$periodo = $this->getPeriodo();
$resposta = null;
if ('mes' == $periodo['tipoFiltro']) {
$from = sprintf('%s|%s|%s', $periodo['to']['tipo'], $periodo['to']['ano'], $periodo['to']['periodo']);
$to = sprintf('%s|%s|%s', $periodo['to']['tipo'], $periodo['to']['ano'], $periodo['to']['periodo']);
$resposta = $this->forward('App\Controller\Componentes\PeriodoController::processa', [
'request' => $request,
'periodoBruto' => ['from' => $from, 'to' => $to],
]);
} elseif ('ano' == $periodo['tipoFiltro']) {
$from = sprintf('%s|ND|%s', $periodo['to']['tipo'], $periodo['to']['periodo']);
$to = sprintf('%s|ND|%s', $periodo['to']['tipo'], $periodo['to']['periodo']);
$resposta = $this->forward('App\Controller\Componentes\PeriodoController::processa', [
'request' => $request,
'periodoBruto' => ['from' => $from, 'to' => $to],
]);
} else {
$this->limpaPeriodos();
}
return $resposta;
}
/**
* Converte um período múltiplo (range) para período único, útil quando for mudar de visão de gestor -> avaliado
* Caso o filtro seja mês e o período inicial e final sejam iguais (período unico), será atribuido o período inicio para janeiro do mesmo ano.
*/
public function trataPeriodoUnicoParaMultiplo()
{
$request = new Request();
$periodo = $this->getPeriodo();
$resposta = null;
if ('mes' == $periodo['tipoFiltro']) {
$from = sprintf('%s|%s|%s', $periodo['to']['tipo'], $periodo['to']['ano'], $periodo['to']['periodo']);
$to = sprintf('%s|%s|%s', $periodo['to']['tipo'], $periodo['to']['ano'], $periodo['to']['periodo']);
if ($from == $to) {
$from = sprintf('%s|%s|01', $periodo['to']['tipo'], $periodo['to']['ano']);
$resposta = $this->forward(
'App\Controller\Componentes\PeriodoController::processa',
[
'request' => $request,
'periodoBruto' => ['from' => $from, 'to' => $to],
]
);
}
}
return $resposta;
}
/**
* Método para remover na seção e modificar o período caso o avaliado caso a visão anterior seja diferente da atual.
*
* @param $rotas será as rotas adicionais que também compõem o controller
* @param $tipo Constante que indicará qual tratamento do período será feito
* - Se passar a constante PERIODO_UNICO_PARA_MULTIPLO será executada a função trataPeriodoUnicoParaMultiplo()
* - Se passar a cosntante PERIODO_MULTIPLO_PARA_UNICO será executada a função trataPeriodoMultiploParaUnico()
*/
public function trataPeriodoAvaliado($rotas, $tipo)
{
if ($this->getSession()->has('visao') && !in_array($this->getSession()->get('visao'), $rotas) && $this->getSession()->get('visao') != $this->getCurrentRoute()) {
//* Converte um período multiplo (range) para período único, útil quando for mudar de visão de gestor -> avaliados
$this->limpaAvaliado();
if (Custom2IMController::PERIODO_UNICO_PARA_MULTIPLO == $tipo) {
$this->trataPeriodoUnicoParaMultiplo();
} elseif (Custom2IMController::PERIODO_MULTIPLO_PARA_UNICO == $tipo) {
$this->trataPeriodoMultiploParaUnico();
} else {
// Para configurar outra tipo de conversão de período basta configurar uma constante, criar uma função e testar aqui
throw new \Exception('Configure o tipo de conversão que deverá ser feita');
}
}
}
/**
* Metodo para validar objetos com base nos asserts especificado na entidade.
*
* @param $filledObj objeto com informações que serão persistidas no banco de dados
* @param $validator interface de validação Symfony\Component\Validator\Validator\ValidatorInterface
*
* @return 1 - Retorna um array vazio para caso não seja encontrado nenhum erro.
* 2 - Retorna um array com as não conformidades do objeto com os asserts da entidade.
*/
public function validarEntity($filledObj, ValidatorInterface $validator): array
{
$validacao = $validator->validate($filledObj);
$erros = [];
if (count($validacao) > 0) {
$contErros = count($validacao);
for ($i = 0; $i < $contErros; ++$i) {
$erros[] = $validacao[$i]->getMessage();
}
}
return $erros;
}
/**
* Metodo para setar filtros de ordenação em sessão.
*
* @param string $nomeComponente
*
* @author Guilherme Arduino
*
* @version 1.0.0
*/
public function setFiltros($nomeComponente)
{
$ascendencia = $this->getCurrentRequest()->query->get($nomeComponente.'_acendencia', $this->getCurrentRequest()->getSession()->get($nomeComponente.'_acendencia', null));
$order = $this->getCurrentRequest()->query->get($nomeComponente.'_order', $this->getCurrentRequest()->getSession()->get($nomeComponente.'_order', null));
//se a chamada da action veio pelo clica na ordenação dos campos
if ('true' == $this->getCurrentRequest()->query->get('ordenacao')) {
if ($ascendencia) {
if ('ASC' == $ascendencia) {
$ascendencia = 'DESC';
} else {
$ascendencia = 'ASC';
}
} else {
$ascendencia = 'ASC';
}
}
$this->getSession()->set($nomeComponente.'_acendencia', $ascendencia);
$this->getSession()->set($nomeComponente.'_order', $order);
$this->getSession()->set($nomeComponente.'_ordem', $order && $ascendencia ? $order.' '.$ascendencia : null);
}
/**
* Metodo para setar paginação em sessão.
*
* @param PaginatorInterface $paginator
* @param mixed $nome_componente
*
* @author Guilherme Arduino
*
* @version 1.0.0
*/
public function setPaginacao(string $nomeComponente, int $pag_linhas, array $dados, $nome_componente = ''): SlidingPagination
{
$this->paginator->setDefaultPaginatorOptions(['nomeDono' => $nomeComponente]);
$this->paginator->setDefaultPaginatorOptions(['nome_componente' => $nome_componente]);
$this->paginator->setDefaultPaginatorOptions(['paginasConfig' => $pag_linhas]);
$this->paginator->setDefaultPaginatorOptions(['numRows' => $this->getCurrentRequest()->query->get($nomeComponente.'_numRows', $this->getCurrentRequest()->getSession()->get($nomeComponente.'_numRows', $pag_linhas))]);
$page = $this->getCurrentRequest()->query->get($nomeComponente.'_page', $this->getCurrentRequest()->getSession()->get($nomeComponente.'_page', 1));
$numRows = $this->getCurrentRequest()->query->get($nomeComponente.'_numRows', $this->getCurrentRequest()->getSession()->get($nomeComponente.'_numRows', $pag_linhas));
$this->getSession()->set($nomeComponente.'_numRows', $numRows);
// se quantidade de linhas mostradas for maior do que a quantidade de linhas em $dados setar pagina para 1
if ($this->getCurrentRequest()->getSession()->get($nomeComponente.'_numRows', $pag_linhas) > count($dados)) {
$page = 1;
} else {
$page = $this->getCurrentRequest()->query->get($nomeComponente.'_page', $this->getCurrentRequest()->getSession()->get($nomeComponente.'_page', $page));
}
$this->getSession()->set($nomeComponente.'_page', $page);
return $this->paginator->paginate($dados, $page, $this->getCurrentRequest()->query->get($nomeComponente.'_numRows', $this->getCurrentRequest()->getSession()->get($nomeComponente.'_numRows', $pag_linhas)));
}
/**
* Retorna os dados da sessão referente a ordem da tabela que está selecionada.
*
* @author Guilherme Arduino
*
* @param string $nomeDonoEspecifico (parametro para especificar um nome para um componente que possua mais de uma listagem sendo carregada na mesma classe)
*
* @version 1.0.0
*
* @return string
*/
public function getFiltroOrdem(?string $nomeDonoEspecifico = null): ?string
{
return $this->getSession()->get(($nomeDonoEspecifico ?? $this->nomeDono).'_ordem');
}
/**
* Retorna o caminho completo da classe.
*
* @return string App\\Controller\\Componentes\\Avaliado\\AlgumaClasse
*
* @author Juliano Luiz da Silva <juliano.silva@2im.com.br>
*/
public function getPathFormatted()
{
return (new \ReflectionClass($this))->getName();
}
/**
* Seta sessions para inicializar visão.
*
* @author Guilherme Arduino
*
* @version 1.0.0
*
* @param bool $periodo_multiplo (define se pode selecionar um range de periodos ou apenas um periodo)
* @param bool $filtra_avaliado (define se seleciona avaliado na visão)
* @param string $no_periodo (define se seleciona periodo na visão)
*/
public function setarSessoesVisao(string $nomeVisao, bool $periodo_multiplo, bool $filtra_avaliado, string $no_periodo = '')
{
$sess = $this->getSession();
$sess->set('visao', $this->getCurrentRoute());
$sess->set('visao_nome', $nomeVisao);
$sess->set('periodo_multiplo', $periodo_multiplo);
$sess->set('filtra_avaliado', $filtra_avaliado);
$sess->set('no-periodo', $no_periodo);
}
/**
* Seta informações para montar o selecionador na ultima posição do breadcrumb.
*
* @author Guilherme Arduino
*
* @version 1.0.0
*
* @param string $url (nome da rota onde será feita a requisição no click [$request->get('_route')])
* @param string $url_param (parametro requisitado na url para a pesquisa)
* @param string $modal_id (chave do modal para recarregar informações no mesmo box)
* @param string $titulo (nome do parametro na requisição com os nomes que irão aparecer no dropdown)
* @param array $array (array com informações do seletor)
*/
public function setarSeletorBreadCrumb(string $url, string $url_param, string $modal_id, string $titulo, ?array $array)
{
$select['url'] = $url;
$select['url_param'] = $url_param;
$select['modal_id'] = $modal_id;
$select['titulo'] = $titulo;
$select['array'] = $array;
return $select;
}
public function renderiza(string $template, array $dados)
{
return $this->render($template, array_merge($this->return, $dados));
}
/**
* @param string $view
* @param array $parameters
* @param Response|null $response
* @return Response
*/
protected function render(string $view, array $parameters = [], Response $response = null): Response
{
if ( defined('static::TEMPLATEBASE') ) {
$view = static::TEMPLATEBASE.$view;
}
return parent::render($view, $parameters, $response);
}
/**
* Lida com a aplicação de filtros para previnir sql injections.
*
* @author Juliano Silva <juliano.silva@2im.com.br>
*
* @param string
* @param mixed $string
*/
public function sanitizeString($string): string
{
return filter_var($string, FILTER_SANITIZE_STRING, ['flags' => FILTER_SANITIZE_MAGIC_QUOTES | FILTER_SANITIZE_SPECIAL_CHARS]);
}
/**
* Retorna a propriedade $translator.
*/
protected function getTranslatorInterface(): \Symfony\Component\Translation\TranslatorInterface
{
return $this->translator;
}
/**
* Retorna a propriedade $validator.
*/
protected function getValidatorInterface(): ValidatorInterface
{
return $this->validator;
}
/**
* @return \Symfony\Component\HttpFoundation\Session\Session\SessionInterface
*/
protected function getSession(): \Symfony\Component\HttpFoundation\Session\SessionInterface
{
return $this->get('session');
}
/**
* Retorna a instancia ativa do objeto de serializer.
*/
protected function getSerializer(): Serializer
{
return new Serializer([new ObjectNormalizer()], [new JsonEncoder()]);
}
/**
* Retorna o array de programa e modelagem que foram selecionados no sistema.
*
* @return array
*/
protected function getPrograma(): ?array
{
return $this->getSession()->get('programa');
}
/**
* Retorna o array de periodos que foram selecionados no sistema.
* @return array
*/
protected function getPeriodo(): ?array
{
return $this->getSession()->get('periodo');
}
/**
* Retorna a string do tipo do periodo que foi selecionado.
* @return string
*/
protected function getTipoPeriodo(): string
{
return $this->getSession()->get('periodo')['tipoFiltro'];
}
/**
* Retorna o array de periodos que foram selecionados no sistema.
* @return string
*/
protected function getPeriodoAnoMes(): string
{
// auxs
$ano = (int) $this->getSession()->get('periodo')['from']['ano'];
$mes = (int) $this->getSession()->get('periodo')['from']['periodo'];
$referencia = ($ano * 100 ) + $mes;
return ( 'ND' == $this->getSession()->get('periodo')['from']['ano'] )
? "{$mes} BETWEEN av.inicio::char(4)::int AND av.fim::char(4)::int"
: "{$referencia} BETWEEN av.inicio AND av.fim";
}
/**
* Retorna o inteiro da referencia do periodo selecionado.
*
* @todo Precisa ver como vamos fazer os tratamentos para Marco, que como usamos BETWEEN em algumas buscas.
*/
protected function getPeriodoReferencia(): int
{
return ( 'ND' == $this->getSession()->get('periodo')['from']['ano'] )
? $this->getSession()->get('periodo')['from']['periodo']
: $this->getSession()->get('periodo')['from']['ano'].$this->get('session')->get('periodo')['from']['periodo'];
}
/**
* Retorna se existe periodo configurado.
*/
protected function hasPeriodo(): bool
{
return $this->getSession()->has('periodo');
}
/**
* Retorna a data formatada.
*
* @param mixed $date
*
* @return \Symfony\Component\HttpFoundation\Request
*/
protected function getDataFormatada($date): string
{
$tipo =$this->getSession()->get('periodo')['from']['tipo'];
switch ($tipo) {
case 'Mensal':
$return = DateHelper::shortDataToFormated($date, true);
break;
default:
$return = $date;
break;
}
return $return;
}
/**
* Limpa sessao periodo.
* @return mixed
*/
protected function limpaPeriodos()
{
return $this->getSession()->remove('periodo') && $this->limpaAvaliado();
}
/**
* Limpa sessao avaliado.
* @return mixed
*/
protected function limpaAvaliado()
{
return $this->getSession()->remove('avaliado');
}
/**
* Limpa sessao cliente.
* @return mixed
*/
protected function limpaCliente()
{
return $this->getSession()->remove('periodo') && $this->getSession()->remove('avaliado') && $this->getSession()->remove('cliente') && $this->getSession()->remove('modelagem');
}
/**
* Limpa filtros setados.
* @return mixed
*/
protected function limpaFiltros()
{
return $this->getSession()->remove('filtros');
}
/**
* Retorna o array de programa e modelagem que foram selecionados no sistema.
* @return array|\App\Entity\Cliente\Modelagem\Modelagem
*/
protected function getModelagem(): ?\App\Entity\Cliente\Modelagem\Modelagem
{
return $this->getSession()->get('modelagem');
}
/**
* Retorna o código do programa que está selecionado.
* @return integer
*/
protected function getIdPrograma(): int
{
return $this->getSession()->get('modelagem')['programa']['id_programa'];
}
/**
* Retorna se existe um programa configurado.
* @return boolean
*/
protected function hasModelagem(): bool
{
return $this->getSession()->has('modelagem');
}
/**
* Lista os icones de determinado programa caso exista.
*
* @author Juliano Silva <juliano.silva@2im.com.br>
*
* @return ?array
*/
protected function getIcones(): array
{
$icones = ['avaliado' => ['codigo' => 'f0f0', 'classe' => 'fa-user-md']];
if ($this->hasPrograma()) {
$config = $this->getModelagem()->getPrograma()->getConfig();
if (isset($config->icone)) {
$configIcones = (array) $config->icone;
} else {
$configIcones = [];
}
if (array_key_exists('avaliado', $configIcones) && !empty($configIcones['avaliado'])) {
$icones = $configIcones;
}
}
return $icones;
}
/**
* Retorna um array com os filtros do sistema.
* @return array
*/
protected function getFiltros(): array
{
return $this->getSession()->get('filtros') ?? ['where' => ''];
}
/**
* Retorna se existem filtros configurados no sistema.
* @return boolean
*/
protected function hasFiltros(): bool
{
return $this->getSession()->has('filtros');
}
/**
* Retorna uma string com os filtros de grupo.
* @return string
*/
protected function getFiltroGrupo(): string
{
return $this->getSession()->get('filtroGrupo') ?? '';
}
/**
* Retorna uma string com os filtros de perfil.
* @return string
*/
protected function getFiltroPerfil(): string
{
return $this->getSession()->get('filtroPerfil') ?? '';
}
/**
* Retorna uma string com os filtros de avaliados.
* @return string
*/
protected function getFiltroAvaliado(): string
{
return $this->getSession()->get('filtroAvaliado') ?? '';
}
/**
* Retorna a Url atual da rota
* @return string
*/
protected function getCurrentRoute(): string
{
return $this->getCurrentRequest()->get('_route');
}
/**
* @return Request
*/
protected function getCurrentRequest(): Request
{
return $this->container->get('request_stack')->getCurrentRequest();
}
/**
* @return array|object|null
*/
protected function getAvaliado()
{
return $this->getSession()->get('avaliado');
}
/**
* @return boolean
*/
protected function isAvaliadoInstanceOfEntity()
{
return $this->getAvaliado() instanceof \App\Entity\Cliente\Modelagem\Avaliado;
}
/**
* @return integer|null
*/
protected function getIdAvaliado()
{
if ( $this->isAvaliadoInstanceOfEntity() ) {
return $this->getAvaliado()->getIdAvaliado();
}
return $this->getAvaliado()[0]['id_avaliado'] ?? $this->getAvaliado()['id_avaliado'];
}
/**
* Modelagens que o avaliado tem cadastro
* @return array|null
*/
protected function getIdModelagemAvaliado(): ?array
{
return array_column($this->getAvaliado(), 'id_modelagem');
}
/**
* @return boolean
*/
protected function hasAvaliado(): bool
{
return $this->getSession()->has('avaliado');
}
/**
* Retorna a sessão com as permissões.
*
* @author Guilherme Arduino
*
* @version 1.0.0
*/
protected function getSessionPermissoes(): array
{
return $this->getSession()->get('permissoesPerfil');
}
/**
* Testa se usuario tem permissão para a visao.
*
* @author Guilherme Arduino
*
* @version 1.0.0
*
* @return \Symfony\Component\HttpFoundation\RedirectResponse
*/
protected function testaPermissoes(int $idVisao, string $rota_default, RouterInterface $router, VisaoRepository $visaoRepository)
{
if (!array_key_exists($idVisao, $this->getSessionPermissoes())) { // testa se o usuario possui permissao para a visao que sera carregada, se não possuir retorna false
// testa se o usuario possui permissao para a rota default para onde será encaminhado caso nao tenha permissão para a visao que tentou encaminhar, caso não possua permissao para o default faz logout do sistema (TESTE PARA EVITAR 429 Too Many Requests)
$default = $visaoRepository->findOneBy(['rota_default' => $rota_default]);
if (!array_key_exists($default->getIdVisao(), $this->getSessionPermissoes())) {
$this->addFlash('error', 'Erro de permissão!');
return new RedirectResponse($router->generate('logout'));
}
// caso usuario tenha permissão ele será redirecionado para a rota_default do respectivo perfil
return new RedirectResponse($router->generate($rota_default));
}
return false;
}
/**
* Monta os drilldowns.
*
* @author Lincoln
*
* @version 1.0.0.0
*
* @return array
*/
protected function montaDrillDown(string $telaAtual, array $breadcumb, string $proximaTela, string $telaAnterior)
{
$request = $this->getCurrentRequest();
$telas = $request->getSession()->get('telas');
if ($request->query->get('voltar')) {
array_pop($telas);
$request->getSession()->set('telas', $telas);
}
if ($telas) {
if (!in_array($telaAtual, $telas['telas'])) {
array_push($telas['telas'], $telaAtual);
array_push($telas['breadcumb'], $breadcumb);
array_push($telas['id_next_tela'], $proximaTela);
array_push($telas['id_prev_tela'], $telaAnterior);
} else {
if ($telas['breadcumb']) {
end($telas['breadcumb']);
$key = key($telas['breadcumb']);
$telas['breadcumb'][$key] = $breadcumb;
}
}
} else {
$telas['telas'] = [$telaAtual];
$telas['breadcumb'] = [$breadcumb];
$telas['id_next_tela'] = [$proximaTela];
$telas['id_prev_tela'] = [$telaAnterior];
}
$request->getSession()->set('telas', $telas);
return [
'status' => true,
];
}
/**
* Retorna se existe um programa configurado.
*/
protected function hasPrograma(): bool
{
return $this->get('session')->has('programa');
}
protected function getPeriodoAvaliacao(): string
{
$periodos = $this->get('session')->get('periodo');
if ('ano' == $periodos['tipoFiltro']) {
return "(av.inicio BETWEEN {$periodos['from']['ano']}01 AND {$periodos['from']['ano']}12) OR (av.fim BETWEEN {$periodos['to']['ano']}01 AND {$periodos['from']['ano']}12)";
}
if('marco' == $periodos['tipoFiltro']) {
return "(av.inicio BETWEEN {$periodos['from']['ano']}01 AND {$periodos['from']['ano']}12) OR (av.fim BETWEEN {$periodos['to']['ano']}01 AND {$periodos['from']['ano']}12)";
}
return "({$periodos['from']['ano']}{$periodos['from']['periodo']} BETWEEN av.inicio AND av.fim) OR ({$periodos['to']['ano']}{$periodos['to']['periodo']} BETWEEN av.inicio AND av.fim)";
}
/**
* Retorna o periodo selecionado atual ou null caso nao tenha nenhum selecionado.
*
* @author Guilherme Arduino Barlatti
*
* @version 1.0.0.0
*
* @return string
*/
protected function getPeridoAtual(): ?string
{
$periodoAtual = $this->getSession()->get('periodo');
$atual = $periodoAtual['from']['titulo'];
if (isset($periodoAtual['to']) && $periodoAtual['from']['periodo'] != $periodoAtual['to']['periodo']) {
$atual .= ' à '.$periodoAtual['to']['titulo'];
}
return $atual ?? null;
}
}