2.1 MvcAbstractController

MvcAbstractController

Durante a programação de um sistema é muito comum que você precise realizar uma mesma tarefa em diversos locais diferentes, por exemplo, verificar se houve POST. Este é um dos motivos para este arquivo existir, assim nós podemos prover a você uma série de métodos que servem de atalho para tarefas repetitivas em seus sistemas.

Neste mesmo modelo, você pode implementar seus próprios métodos aqui apenas extendendo esta classe e apontando o controlador para esta sua nova que recomendamos chamar de AbstractController. [[Você pode encontrar mais detalhes aqui.|2. Controllers e Views#abstractcontroller]]

Mas a menos que sejam estáticos, estes métodos não podem ser acessados da view ou de model, na verdade não podem ser acessados em nenhum lugar fora do escopo do controlador, então para isso você pode criar um arquivo functions.php na raiz de seu projeto e implementar suas próprias funções que serão acessíveis de qualquer lugar. Neste caso basta fazer um include deste seu novo arquivo no index.php ([[aqui neste link|1. Instalação#indexphp]]).

Workflow do SuitUp

Não há segredos, o SuitUp sabe que seu controlador extende a esta classe MvcAbstractController, isso é obrigatório. Alguns métodos desta classe são necessários para o funcionamento do framework e ainda em uma determinada ordem correta. Deste modo é possível criar algumas rotinas em seu sistema para situações específicas.

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
// Com a instancia do seu controlador o SuitUp
// irá chamar os métodos a seguir nesta mesma ordem

// 1. Lançado antes do init e da ação atual
$this->mvc->controller->preDispatch();

// 2. Método init
$this->mvc->controller->init();

// 3. Ação atual (depende da URL)
$this->mvc->controller->{$this->mvc->actionName}();

// 4. Lançado depois da ação atual, antes de mostrar o conteúdo na tela.
$this->mvc->controller->posDispatch();
Você pode sobrescrever estes métodos a vontade, mas no caso do preDispatch e posDispatch não se esqueça de chamar o método original também, caso contrário o SuitUp não funcionará corretamente.

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
namespace ModuleDefault\Controllers;

abstract class AbstractController extends \SuitUp\Mvc\MvcAbstractController
{
    public function preDispatch() {
        // Aqui você pode implementar o que Deus tocar no seu coração

        // Mas não esqueça de chamar o método original
        // para o bom funcionamento do SuitUp
        parent::preDispatch();

        // OU aqui você pode implementar o que Deus tocar no seu coração
    }

    public function posDispatch() {
        // Aqui você pode implementar o que Deus tocar no seu coração

        // Mas não esqueça de chamar o método original
        // para o bom funcionamento do SuitUp
        parent::posDispatch();

        // OU aqui você pode implementar o que Deus tocar no seu coração
    }
}

O que já vem por padrão no SuitUp

A lista abaixo descreve todos os métodos que são padrão do MvcAbstractController e podem ser utilizados dentro de qualquer controlador do seu sistema.

preDispatch init indexAction errorAction
notFoundAction posDispatch getMsgNsp getModuleName
getControllerName getActionName getLayoutName setLayout
renderView addViewVar isViewVar getViewVar
getParams getParam isPost getPost
setLogin isLogged getLogin updateLoginKey
addMsg uploadFile uploadFileImageBase64 getReferer
redirect ajax addSessionFilter getSessionFilter
removeSessionFilter clearSessionFilter

$this->preDispatch();

Lançado antes de qualquer outra coisa no controlador, executa internamente algumas ações para o bom funcionamento do SuitUp. Não deve ser sobrescrito sem ser chamado internamente com parent::preDispatch();.

$this->init();

Lançado após o preDispatch(), mas antes da ação atual. Até o momento este método não executa nenhuma ação interna do SuitUp, portanto não precisa ser chamado com parent::init(); ao ser sobrescrito, embora isso seja uma boa prática para prevenir conflitos com versões futuras. :eyes:

$this->indexAction();

A ação index é chamada quando o nome da ação não é apontada na url ex.: http://seusite.dev/ que chamará o módulo default, o controlador index e a ação index. Este método ser incluído no MvcAbstractController apenas previne o caso de um novo controlador não implementar esta ação. Caso seja sobrescrito não necessita ser invocado com parent::indexAction();.

$this->errorAction();

Sempre que o SuitUp encontra pelo caminho uma Exception não tratada, ele dispara para a tela de erros do [[ErrorController|2.2 ErrorController]]. Dentro desse controlador ErrorController ele irá executar esta ação se não for o tipo de erro 404 (Página Não Encontrada).

Leia mais em: [[ErrorController|2.2 ErrorController]]

$this->notFoundAction();

Sempre que o SuitUp encontra pelo caminho uma Exception não tratada, ele dispara para a tela de erros do [[ErrorController|2.2 ErrorController]]. Esta Exception pode ter sido lançada por causa de um módulo, controlador ou ação que não foi encontrada, para estes casos é que esta ação é lançada no ErrorController.

Leia mais em: [[ErrorController|2.2 ErrorController]]

$this->posDispatch();

Lançado depois de qualquer ação no controlador, executa internamente algumas ações para o bom funcionamento do SuitUp. Não deve ser sobrescrito sem ser chamado internamente com parent::posDispatch();.

$this->getMsgNsp();

Nós não queremos misturar as mensagens disparadas em módulos diferentes do seu sistema, por isso, este método retorna o namespace do módulo atual. Mas o que são estas mensagens?

Mais adiante você notará que existe o método $this->addMsg($msg, $type = MsgType::INFO, $withRedirect = false);, com o parâmetro $withRedirect = true o SuitUp irá guardar sua mensagem na $_SESSION para apresentá-la somente na próxima página, normalmente usado antes a um $this->redirect($to);

$this->getModuleName();

Retorna o nome do módulo atual.

Exemplo:
Módulo padrão (http://seusite.dev/), retorna: default
Módulo Admin (http://seusite.dev/admin), retorna: admin

$this->getControllerName();

Retorna o nome do controlador atual.

Exemplo:
http://seusite.dev/: Retorna index
http://seusite.dev/admin/usuario: Retorna usuario

$this->getActionName();

Retorna o nome da ação atual.

Exemplo:
http://seusite.dev/: Retorna index
http://seusite.dev/admin/usuario/editar: Retorna editar

$this->getLayoutName();

Retorna o nome do layout que está sendo utilizado no momento. [[Clique aqui|3. Layouts]] para entender melhor sobre o que se trata layout.

$this->setLayout($name, $path = null);

1
2
(string) $name; // Nome do novo layout, este é o nome do arquivo sem o `.phtml`, por isso não use espaços ou caractéres especiais
(string) $path; // Caminho até o novo arquivo de layout

É possível mudar o layout em tempo de execução, segue o exemplo:

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
// Execute este código no seu controlador para ver o que acontece
public function indexAction()
{
    // Imprime o nome do layout atual
    echo dump($this->getLayoutName());

    // troca o layout
    $this->setLayout('error');

    // Imprime o novo nome do layout
    dump("\n<br/>"$this->getLayoutName());
}

$this->renderView($renderViewName, $vars = array(), $renderViewPath = null);

1
2
3
(string) $renderViewName;  // Nome do arquivo que será renderizado
(array)  $vars;            // Variáveis que estarão disponíveis neste arquivo
(string) $renderViewPath;  // Caminho até este arquivo.

Renderizar uma view é um termo que significa que você quer capturar um arquivo html e seu conteúdo, podendo inclusive passar a ela variáveis. Isso é muito comum ao por exemplo, enviar um e-mail HTML ao seu cliente com dados de um pedido.

$this->addViewVar($name, $value = null);

1
2
(string) | (array) $name; // Nome da variável que será acessível no controlador ou um array associativo com nome => valor
(mixed) $value;           // No caso do parâmetro anterior não ser um array este será o valor desta variável

Após realizar as ações que você precisa que seu controlador realize você possivelmente vai precisar passar para a view alguma informação, este método existe para isso.

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
// File: Qualquer arquivo Controller
public function indexAction()
{
    $something = ["a", 156, 0.5, 'c'];
    $other = "A value from your mind";

    // Pode transferir esta variavel para a view assim
    $this->addViewVar('thing', $something);

    // Ou pode passar todas as variáveis de uma só vez no final da acao (metodo)
    $this->addViewVar(array(
        'thing' => $something,
        'otherStuff' => $other,
    ));
}

Automaticamente estes valores estarão disponíveis na respectiva view. Neste caso ficarão acessíveis por $thing e $otherStuff;

$this->isViewVar($name);

1
(string) $name; // Nome da variável que está procurando

Você pode verificar se uma variável já foi passada para a view utilizando este método.

$this->getViewVar($name);

1
(string) $name; // Nome da variável que está procurando

Mesmo antes da view você pode recuperar o valor de uma variável utilizando este método.

$this->getParams();

Este método retorna todos os parâmetros passados pela URL (query string GET) juntamente com os parâmetros definidos nas [[rotas|6. Rotas]]. Para mais informações sobre rotas [[clique aqui|6. Rotas]].

$this->getParam($name, $default = null);

1
2
(string) $name;    // Nome do parâmetro que você está tentando capturar
(mixed)  $default; // Valor que será retornado caso o parâmetro não exista

A exemplo do método $this->getParams(); este método irá retornar apenas o próprio parâmetro apontado por $name e o valor apontado em $default caso este não exista.

$this->isPost();

Este método é extremamente simples, mas igualmente importante. Com ele é possível se houve um POST de formulário ou de WebService. Retorna somente true ou false.

$this->getPost($name = null, $default = null);

1
2
(string) $name;   // Nome do item de post que deseja capturar
(mixed) $default; // Valor que será retornado caso este item não exista

Você pode utilizar este método para capturar todo o POST ou apenas um índice específico apenas utilizando ou não os parâmetros que ele leva.

$this->setLogin(array $data = array());

O MvcAbstractController contém o atributo $authNsp que funciona como namespace e te permite sobrescreve-lo para que você possa criar uma sessão diferente para cada módulo do seu sistema. Isso significa que mesmo sendo um único sistema você pode fazer login com usuários diferentes em vários módulos ao mesmo tempo.

Login simples

1
2
3
4
5
6
    // File: Qualquer controlador

    // Vamos lá, isso é só um exemplo...
    $loginData = $this->getPost();

    $this->setLogin($loginData);
Note que neste caso simplesmente gravamos os dados do usuário diretamente na sessão.

Login com namespace por módulo

1
2
3
4
5
6
    // File: AbstractController do seu módulo diferentão

    public function __construct() {
        // Apenas seja criativo para criar um namespace legal
        parent::$authNsp = "umNamespaceQualquer";
    }
Note que modificamos o namespace e assim os dados de login ficarão independentes. Depois disso basta seguir o passo anterior para gravar o login em $this->setLogin($loginData).

$this->isLogged();

Retorna true caso exista alguma coisa no namespace atual de login e false do contrário.

static $this->getLogin($key = null, $default = null)();

1
2
(string) $key;    // Um índice para ser buscado
(mixed) $default; // Um valor padrão caso o índice não seja encontrado.

Se o parâmetro $key não for passado então este método retornará tudo que está na sessão de login deste namespace. Quando existe o parâmetro $key o método tenta retorna-lo e caso não encontre este índice irá retornar o valor de $default.

Algo interessante de se notar neste método é que ele pode ser acessado estaticamente, ou seja, até mesmo nas views você pode acessa-lo.

Exemplo:

1
<h2>Nome: <?php echo \SuitUp\Mvc\MvcAbstractController::getLogin('name'); ?></h2>

Mas não é necessário. Dentro das views é possível usar a variável $login em vez disso.

static $this->updateLoginKey($key, $value);

1
2
(string) $key;  // Um indice já existente para alterar
(mixed) $value; // Valor

Atualiza um índice da sessão de login para o módulo. Se o índice não for encontrado o método não faz nada.

A exemplo do getLogin este método também é estático e pode ser acessado de qualquer lugar.

$this->addMsg($msg, $type = MsgType::INFO, $withRedirect = false);

1
2
3
(string) $msg;       // Mensagem que você quer disparar
(string) $type       // Tipo de mensagem
(bool) $withRedirect // Com ou sem redirecionamento

Este método adiciona uma mensagem separando por tipo para o sistema disparar. Para capturar esta mensagem somente após um redirecionamento basta passar o terceiro parâmetro $withRedirect como true.

Desculpa, temos que falar sobre o Bootstrap. Atualmente a maioria dos sites são construídos com a ajuda do Bootstrap e consigo ele traz os alerts que são boxes coloridos feitos com intuito de exibir mensagens aos usuários. Por padrão o Bootstrap utiliza 4 tipos de boxes (alert-success, alert-warning, alert-info e alert-danger). Por isso se você abrir [[este arquivo do SuitUp|https://github.com/braghimsistemas/suitup-php/blob/master/src/Enum/MsgType.php]] você verá exatamente estes quatro tipos de mensagens.

Você pode criar seus próprios tipos de mensagens sem problemas, mas se for fazer isso nós recomendamos que seja feito em forma de constantes para assim evitar erros de digitação e consequentes bugs desnecessários.

Para recuperar nas views e layout as mensagens disparadas [[clique aqui|3. Layouts#mensagens-de-layout]].

$this->uploadFile($file, $where, $exitFilename = null, array $allowedExt = array('jpeg', 'jpg', 'pdf', 'png', 'gif'));

1
2
3
4
(array) $file;          // Índice do arquivo em $_FILES
(string) $where;        // Caminho para onde você quer mover o arquivo depois do upload
(string) $exitFilename; // Nome do arquivo depois do upload
(array) $allowedExt;    // Lista de ext's aceitas pelo upload

Este método efetua o upload de arquivos via formulário HTML.

Se você abrir o arquivo composer.json do SuitUp verá que há um require verot/class.upload.php. Nós não estamos tentando fazer com que o SuitUp seja seu único caminho para fazer tudo que você precisa em seu aplicativo. Na verdade apoiamos a utilização de bibliotecas que são de fácil manuseio e fazem todo o trabalho duro por isso em vez de fazermos nosso próprio módulo para upload de arquivos recomendamos [[verot/class.upload.php|https://github.com/verot/class.upload.php]] que já está há anos no mercado e sempre cumpriu até mais do que o necessário para uploads de arquivos.

Se sentir que este método não supre suas necessidades, fique a vontade para sobrescreve-lo em seu AbstractController.

Atenção.

Este método joga uma Exception em caso de erros, portanto não esqueça de "cobrir" seu código com um try, catch

$this->uploadFileImageBase64($file, $maxFilesize = 524288);

1
2
(array) $file;     // Arquivo feito upload ($_FILES)
(int) maxFilesize; // Tamanho máximo para o arquivo

É possível salvar uma imagem não como arquivo, mas como string utilizando para isso o base64, para isso basta utilizar este método.

Atenção.

Este método joga uma Exception em caso de erros, portanto não esqueça de "cobrir" seu código com um try, catch

$this->getReferer();

Este método retorna a URL em que o usuário esteve antes de chegar à página atual. Faz isso através de $_SERVER['HTTP_REFERER'].

$this->redirect($to);

1
(string) $to; // Local para onde quer redirecionar

Este método é simplesmente um atalho para header('Location: $to');.

Procure utilizar este método sempre precedido pelo return dentro da ação

1
2
3
4
public function indexAction()
{
    return $this->redirect('/');
}

$this->ajax(array $data);

1
(array) $data // Array que será transformado em JSON e retornado

É muito comum que em vez de html haja a necessidade de alguma ação retornar um JSON, seja para um AJAX ou até mesmo para construir um módulo de WebService. Para isso basta que no final do sua ação você passe a este método um array modelado com a forma que você deseja para seu JSON. Este próprio método evita que seja renderizado qualquer HTML e dispara também o header("Content-Type: application/json; Charset=UTF-8").

Atenção!

Qualquer alteração após a chamada a este método não tem nenhum efeito, pois ele próprio faz um exit o que faz com que a aplicação pare totalmente.


SessionFilter (Sessão de Filtros)

Você provavelmente já precisou utilizar dados de um formulário para filtrar uma lista de resultados. Para fazer isso você pode utilizar GET que recupera os parâmetros de filtro pela URL ou POST que os esconde e torna o formulário mais seguro.

Em primeiro lugar gostamos de frisar que na maioria dos casos utilizar GET é sim uma boa opção pelo fato de que assim os filtros podem ser compartilhados, mas existem casos em que isso pode ser perigoso ou que você não queira deixar a URL feia.

Seja como for ao efetuar esses filtros por POST e utilizar paginação ao mesmo tempo os dados do filtro serão perdidos após a primeira página, para isso temos aqui estes métodos abaixo que te ajudam de modo simples a manter os filtros mesmo utilizando paginação.

Como funciona isso?
Através de um namespace específico para cada ação do seu sistema o SuitUp separa os dados deste filtro e os guarda na sessão ($_SESSION).

Exemplo de workflow funcional.

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
<?php
// File: ModuleDefault/Controllers/IndexController.php

namespace ModuleDefault\Controllers;

class IndexController extends AbstractController
{
    public function indexAction()
    {
        // Verifica se houve post
        if ($this->isPost()) {

            // Verifica se foi clicado no botão para limpar o formulário
            // Isso é feito com <button type="submit" name="clear">Limpar</button>
            if ($this->getPost('clear', false)) {
                $this->clearSessionFilter();
            } else {

                // Adiciona ou substitui os filtros na sessao
                // unica para esta acao
                $this->addSessionFilter($this->getPost());

                // Redireciona para a mesma tela apenas para evitar
                // a confirmação de reenvio de formulário do navegador
                return $this->redirect('/');
            }
        }

        $userBo = new ModuleDefault/Model/UserBusiness();

        // Efetua a consulta da lista normalmente
        // ESTA LISTA NORMALMENTE SERA PAGINADA
        $list = $userBo->getList($this->getSessionFilter());

        // Na view esta lista será acessível por $usersList
        $this->addViewVar(array(
            'usersList' => $list,
        ));
    }
}

$this->addSessionFilter($name, $value = null);

1
2
(string | array) $name; // Adiciona uma lista ou um índice a sessão
(mixed) $value;         // No caso de adicionar um índice este será seu valor

Adiciona ou atualiza um ou vários itens a um espaço único por ação na sessão de filtros.

$this->getSessionFilter();

Retorna todos os itens de sessão para o controlador e ação atuais.

$this->removeSessionFilter($key = null);

1
(string) $key; // Índice que quer remover

Remove um item da sessão de filtros único por ação.

$this->clearSessionFilter();

Remove todos os filtros na sessão de filtros únicos para a ação atual.