PHP com MVC - Atualização 2

Para acessar os projetos desse curso executar o comando $ composer server no diretório do projeto. Acessar no endereço localhost:8081



Aula 02 a 04 - Arquitetando um projeto / Camadas de uma aplicação / O que é MVC
Um modelo de estrutura de diretórios para trabalhar com MVC segue a seguinte estrutura:
  • src - Source
  • app - Aplicação
  • vendor - Composer
  • composer.json - Pacotes, autoload, scripts
  • bootstrap.php - Inicia a aplicação toda
  • public/index.php - Front Controller
O mínimo para um projeto web é:
  • Container de injeção de dependencias
  • Rotas
A injenção de dependencias é feita através de classes que irão executar cada um dos módulos necessários para a aplicação.
As rotas são responsáveis por resolver todas as ações da aplicação pela URL do navegador.
Porém só essas duas camadas não são suficientes para evitar a modelagem de páginas html, inclusão de instruções e chamadas PHP no meio do código, etc. Para isso a estrutura do projeto deverá conter:
  • Gerenciamento de dependências
  • Rotas
  • Model
  • View
  • Controller
  • Eventos
  • Middlewares
Seguindo esses passos o arquivo de rotas será o responsável por receber o caminho para onde o usuário deseja ir e indicar ao controller qual ação tomar, seja uma requisição a camada de model, seja uma renderização de view.
Os eventos executam tarefas paralelas ao MVC, como envio de e-mail ou consumo de uma API.
Aula 05 - Autoload de classes
Iniciamos o projeto criando um arquivo composer.json para a preparação do autoload. Fizemos a criação através do composer init e inserimos os dados do autolozad manualmente:
"require": {},
"autoload": {
"psr-4": {
"SON\\": "src",
"App\\": "app"
}
}
Todas as classes que estiverem no escopo do namespace SON serão responsáveis pelo core do sistema e as classes do namespace APP serão a aplicação em si.
Criamos o arquivo Controller.php que será responsável por manipular a aplicação. Em princípio para testes retornamos apenas o comando self::class para retornar o nome da classe.
Criamos o arquivo bootstrap.php que irá executar a aplicação e nele incluimos o autoload e instanciamos a classe Controller para exibir o resultado.
A função do autoload do Composer é incluir os arquivos cada vez que fazemos uma referencia a ele pelo seu namespace, ou seja, sempre que ele identificar uma referencia do namespace definido ele realiza o include no caminho definido pelo autoload.
Aula 06 a 07 - Conhecendo nosso router / Trabalhando com coleções e Array Access
O arquivo de rotas será responsável por fazer a resolução dos controllers. Ele deve retornar o controller definido sempre que for chamado o caminho no navegador.
Vamos criar o arquivo Router.php que terá a classe de mesmo nome.
Relembrando vamos criar métodos com visibilidade private que só podem ser executadas na classe. O método protected só pode ser utilizado pela classe e pelas classes que extenderem a classe e o public pode ser utilizado em qualquer lugar.
Criamos uma arquivo router.php que conterá as rotas especificamente. Nele será especificado para cada rota um array contendo o caminho para o controlador que pode ser especificado pela string do caminho entre '' ou pelo caminho seguido de ::class (indica que o controller é aquela classe) e o action. Em um Controller todos os métodos são chamados action.
Entretanto não podemos utilizar classes como valores em arrays. Para permitir que essa coleção de dados seja utilizada no PHP podemos utilizar o ArrayAccess. Para isso devemos implementar essa classe na classe desejada e criar os métodos 'offsetExists', 'offsetGet', 'offsetSet', 'offsetUnset' Com isso podemos passar objetos como se fossem arrays.
Aula 08 - Resolvendo rotas para controllers
Para resolver as rotas agora criamos um método handler() na classe Router que irá verificar o caminho recebido pela variável PHP $_SERVER['PATH_INFO'] e remover caso exista a '/' ao final do caminho. Por fim se o método do ArrayAccess verificar que existe valor no parametro ele retorna o valor da rota a instanciar e o valor da action.
Com isso podemos instanciar o objeto (UserControler) e executar o método de acordo com a action.
Aqui voltamos para o mesmo problema de sempre: a inclusão do .htaccess para resolução de rotas.
Após alguma pesquisa entendi qual o problema com o .htaccess. Precisamos configurar no Apache a opção AllowOverride.
Para o XAMPP basta ajustar o arquivo httpd.conf.
Já na imagem do Docker tive que fazer alguns passos a mais. Primeiro devemos habilitar o AllowOverride. Em seguida (para a imagem php:7.4-apache) devemos copiar o mod rewrite copiando o arquivo: $ cp /etc/apache2/mods-available/rewrite.load /etc/apache2/mods-enabled/ Com isso o sistema passa a funcionar com o arquivo .htaccess.
Aula 09 a 10 - Renderizando html / Automatizando resolução da view
Criamos um novo método na classe Controller que fará a renderização dos elementos html.
Esse método recebe um array de dados e uma string que conterá o caminho para a página a ser renderizada.
Esse método será executado pelo UserController de acordo com o action selecionado e irá executar as páginas gravadas no diretório de templates.
Em seguida vamos alterar o modo de seleção do diretório de template do html. Inicialmente estavamos passando o valor por parametro, mas faremos uma alteração para utilizar parte do nome do Controller para fazer essa seleção. Para isso criamos um método que recebe a classe que está chamando o método render() e formata seu nome (no caso a classe é UsersController e o valor retornado deve ser users).
Com isso se padronizarmos os diretórios no padrão correto (primeiro nome da classe do Controller em letra minuscula) podemos inseri-lo na construção do path para o template.
Recebido esse valor concatenamos uma '/' e para recuperar o nome da action foi utilizado um artifício que não achei muito prático. Utilizou-se uma função do PHP chamada debug_backtrace() que retorna um array com os últimos métodos executados. Sabendo que o método que queremos está no indice 1 do array na chave function recuperamos o valor da action. Isso parece ser uma gambiarra (utilizar o historico de métodos). Acho melhor passar a action como parametro.
Aula 11 a 13 - Elaborando a camada de model / Resolvendo dependencias de classes automaticamente parte 1 e parte 2
Criamos a classe Model que será instanciada como parametro no construtor da classe Controller.
Criamos uma nova classe User que extende a classe Model. E passamos a instanciar essa classe no arquivo bootstrap como parametro do Controller.
Agora vamos trabalhar com uma API PHP chamada Reflection. Com isso deixaremos de instanciar as classes UserController (passsada pelo router['class']) e Models\User (passada pelo router['action']) no arquivo bootstrap e passamos a tratá-los na classe Resolver.
A classe Resolver instancia a classe PHP ReflectionClass (veja documentação em PHP Documentation ) que reporta informações sobre uma classe e possui diversos métodos.
No arquivo bootstrap instanciamos a classe Resolver e executamos o método handler() passando a class e a action como parametro. Esse handler() verifica se a classe passada por parametro tem um construtor e caso contrário instancia um novo objeto com a classe recebida.
A partir daqui a abstração vai além do que eu pude entender...
Aula 14 a 15 - Elaborando a classe resolver / Finalizando a model
Continuando a abstração, foi criado o arquivo resolver para passar os dados do DB (através de PDO).
Foi criada uma classe Collection para armazenar os métodos necessários para a classe ArrayAccess do PHP para que possamos utilizá-la em outras classes. Assim passamos a utilizar o ArrayAccess nas classes Router e Resolver.
Criados métodos no Model para recuperar o nome da tabela do DB consultada e retornar as querys definidas para os controllers das páginas para popular os templates.
Aula 06 -