Flight é um framework rápido, simples e extensível para PHP. É bastante versátil e pode ser usado para construir qualquer tipo de aplicação web. Ele é construído com simplicidade em mente e é escrito de uma maneira fácil de entender e usar.
Aqui está um artigo breve sobre por que você deve usar um framework. É uma boa ideia entender os benefícios de usar um framework antes de começar a usá-lo.
Além disso, um excelente tutorial foi criado por @lubiana. Embora não entre em muitos detalhes sobre o Flight especificamente, este guia irá ajudá-lo a entender alguns dos principais conceitos em torno de um framework e por que eles são benéficos de usar. Você pode encontrar o tutorial aqui.
Se você está migrando de outro framework como Laravel, Slim, Fat-Free ou Symfony para o Flight, esta página irá ajudá-lo a entender as diferenças entre os dois.
Aprenda a carregar automaticamente suas próprias classes em sua aplicação.
Aprenda como gerenciar rotas para sua aplicação web. Isso também inclui agrupamento de rotas, parâmetros de rota e middleware.
Aprenda como usar middleware para filtrar solicitações e respostas em sua aplicação.
Aprenda como lidar com solicitações e respostas em sua aplicação.
Aprenda como enviar respostas para seus usuários.
Aprenda como usar o mecanismo de visualização incorporado para renderizar seus modelos HTML.
Aprenda como proteger sua aplicação contra ameaças de segurança comuns.
Aprenda como configurar o framework para sua aplicação.
Aprenda como estender o framework adicionando seus próprios métodos e classes.
Aprenda como usar o sistema de eventos para adicionar ganchos aos seus métodos e métodos internos do framework.
Aprenda como usar contêineres de injeção de dependência (DIC) para gerenciar as dependências de sua aplicação.
Saiba mais sobre os métodos principais do framework.
A compatibilidade com versões anteriores foi em grande parte mantida, mas existem algumas alterações das quais você deve estar ciente ao migrar da v2 para a v3.
Existem alguns problemas comuns com os quais você pode se deparar ao usar o Flight. Esta página irá ajudá-lo a solucionar esses problemas.
Você pode parar o framework a qualquer momento chamando o método halt:
halt
Flight::halt();
Você também pode especificar um código de status HTTP opcional e uma mensagem:
HTTP
Flight::halt(200, 'Volto em breve...');
Chamar halt irá descartar qualquer conteúdo de resposta até esse ponto. Se você quiser parar o framework e exibir a resposta atual, use o método stop:
stop
Flight::stop();
Todos os erros e exceções são interceptados pelo Flight e passados para o método error. O comportamento padrão é enviar uma resposta genérica de HTTP 500 Erro Interno do Servidor com algumas informações de erro.
error
HTTP 500 Erro Interno do Servidor
Você pode substituir esse comportamento para suas próprias necessidades:
Flight::map('error', function (Throwable $error) { // Lidar com o erro echo $error->getTraceAsString(); });
Por padrão, os erros não são registrados no servidor web. Você pode habilitar isso alterando a configuração:
Flight::set('flight.log_errors', true);
Quando um URL não pode ser encontrado, o Flight chama o método notFound. O comportamento padrão é enviar uma resposta de HTTP 404 Não Encontrado com uma mensagem simples.
notFound
HTTP 404 Não Encontrado
Flight::map('notFound', function () { // Lidar com não encontrado });
Laravel é um framework completo que possui todas as funcionalidades e uma incrível ecossistema focado no desenvolvedor, mas com um custo em termos de desempenho e complexidade. O objetivo do Laravel é fornecer ao desenvolvedor o mais alto nível de produtividade e tornar as tarefas comuns fáceis. Laravel é uma ótima escolha para desenvolvedores que desejam construir aplicações web empresariais completas. Isso vem com alguns compromissos, especificamente em termos de desempenho e complexidade. Aprender o básico do Laravel pode ser fácil, mas ganhar proficiência no framework pode levar algum tempo.
Também existem tantos módulos do Laravel que os desenvolvedores frequentemente sentem que a única maneira de solucionar problemas é através desses módulos, quando na verdade você poderia usar apenas outra biblioteca ou escrever seu próprio código.
A compatibilidade com versões anteriores foi em grande parte mantida, mas há algumas mudanças das quais você deve estar ciente ao fazer a migração da v2 para a v3.
O buffering de saída é o processo pelo qual a saída gerada por um script PHP é armazenada em um buffer (interno ao PHP) antes de ser enviada ao cliente. Isso permite que você modifique a saída antes de enviá-la ao cliente.
Em uma aplicação MVC, o Controlador é o "gerente" e ele gerencia o que a visualização faz. Ter saída gerada fora do controlador (ou no caso do Flight, às vezes em uma função anônima) quebra o padrão MVC. Essa mudança visa estar mais alinhada com o padrão MVC e tornar o framework mais previsível e fácil de usar.
Na v2, o buffering de saída era tratado de uma maneira em que não estava consistentemente fechando seu próprio buffer de saída, o que tornava os testes unitários e streaming mais difíceis. Para a maioria dos usuários, essa mudança pode não afetá-lo de fato. No entanto, se você estiver dando um echo no conteúdo fora de callables e controladores (por exemplo, em um hook), provavelmente terá problemas. Dar echo no conteúdo em hooks e antes do framework realmente executar pode ter funcionado no passado, mas não funcionará mais para frente.
// index.php require 'vendor/autoload.php'; // apenas um exemplo define('START_TIME', microtime(true)); function hello() { echo 'Olá Mundo'; } Flight::map('hello', 'hello'); Flight::after('hello', function(){ // isso na verdade está bem echo '<p>Esta frase de Olá Mundo foi trazida para você pela letra "H"</p>'; }); Flight::before('start', function(){ // coisas como esta causarão um erro echo '<html><head><title>Minha Página</title></head><body>'; }); Flight::route('/', function(){ // isso na verdade está ok echo 'Olá Mundo'; // Isso também deve estar ok Flight::hello(); }); Flight::after('start', function(){ // isso causará um erro echo '<div>Sua página carregou em '.(microtime(true) - START_TIME).' segundos</div></body></html>'; });
Ainda é possível manter o seu código antigo exatamente como está sem a necessidade de uma reescrita para fazê-lo funcionar com a v3? Sim, é possível! Você pode ativar o comportamento de renderização v2 definindo a opção de configuração flight.v2.output_buffering como true. Isso permitirá que você continue usando o antigo comportamento de renderização, mas é recomendado corrigi-lo para o futuro. Na v4 do framework, isso será removido.
flight.v2.output_buffering
true
// index.php require 'vendor/autoload.php'; Flight::set('flight.v2.output_buffering', true); Flight::before('start', function(){ // Agora isso estará bem echo '<html><head><title>Minha Página</title></head><body>'; }); // mais código
Se você estava chamando diretamente métodos estáticos para Dispatcher como Dispatcher::invokeMethod(), Dispatcher::execute(), etc., você precisará atualizar seu código para não chamar diretamente esses métodos. Dispatcher foi convertido para ser mais orientado a objeto, de modo que Contêineres de Injeção de Dependência possam ser usados de forma mais simples. Se você precisar invocar um método semelhante ao que o Dispatcher fazia, você pode usar manualmente algo como $result = $class->$method(...$params); ou call_user_func_array() em vez disso.
Dispatcher
Dispatcher::invokeMethod()
Dispatcher::execute()
$result = $class->$method(...$params);
call_user_func_array()
halt()
stop()
redirect()
error()
O comportamento padrão antes da versão 3.10.0 era limpar tanto os cabeçalhos quanto o corpo da resposta. Isso foi alterado para limpar apenas o corpo da resposta. Se você precisar limpar também os cabeçalhos, você pode usar Flight::response()->clear().
Flight::response()->clear()
Você pode personalizar determinados comportamentos do Flight definindo valores de configuração através do método set.
set
A seguir está uma lista de todas as configurações disponíveis:
?string
bool
string
Content-Length
Existe adicionalmente uma outra configuração para o carregador. Isso permitirá que você carregue classes com _ no nome da classe.
_
// Ativar o carregamento de classe com underscores // Por padrão é verdadeiro Loader::$v2ClassLoading = false;
O Flight permite que você salve variáveis para que possam ser usadas em qualquer lugar de sua aplicação.
// Salve sua variável Flight::set('id', 123); // Em outro lugar de sua aplicação $id = Flight::get('id');
Para ver se uma variável foi definida, você pode fazer:
if (Flight::has('id')) { // Faça algo }
Você pode limpar uma variável fazendo:
// Limpa a variável id Flight::clear('id'); // Limpa todas as variáveis Flight::clear();
O Flight também utiliza variáveis para fins de configuração.
Todos os erros e exceções são capturados pelo Flight e passados para o método error. O comportamento padrão é enviar uma resposta genérica de HTTP 500 Erro interno do servidor com algumas informações de erro.
HTTP 500 Erro interno do servidor
Você pode substituir esse comportamento conforme suas necessidades:
Flight::map('error', function (Throwable $error) { // Manipular erro echo $error->getTraceAsString(); });
Por padrão, os erros não são registrados no servidor web. Você pode ativá-los alterando a configuração:
Quando uma URL não pode ser encontrada, o Flight chama o método notFound. O comportamento padrão é enviar uma resposta de HTTP 404 Não encontrado com uma mensagem simples.
HTTP 404 Não encontrado
A segurança é muito importante quando se trata de aplicações web. Você deseja garantir que sua aplicação seja segura e que os dados de seus usuários estejam protegidos. Flight fornece uma série de recursos para ajudá-lo a proteger suas aplicações web.
Os cabeçalhos HTTP são uma das maneiras mais fáceis de proteger suas aplicações web. Você pode usar cabeçalhos para evitar clickjacking, XSS e outros ataques. Existem várias maneiras de adicionar esses cabeçalhos à sua aplicação.
Dois ótimos sites para verificar a segurança de seus cabeçalhos são securityheaders.com e observatory.mozilla.org.
Você pode adicionar manualmente esses cabeçalhos usando o método header no objeto Flight\Response.
header
Flight\Response
// Defina o cabeçalho X-Frame-Options para evitar clickjacking Flight::response()->header('X-Frame-Options', 'SAMEORIGIN'); // Defina o cabeçalho Content-Security-Policy para evitar XSS // Nota: este cabeçalho pode se tornar muito complexo, então você vai querer // consultar exemplos na internet para a sua aplicação Flight::response()->header("Content-Security-Policy", "default-src 'self'"); // Defina o cabeçalho X-XSS-Protection para evitar XSS Flight::response()->header('X-XSS-Protection', '1; mode=block'); // Defina o cabeçalho X-Content-Type-Options para evitar sniffing MIME Flight::response()->header('X-Content-Type-Options', 'nosniff'); // Defina o cabeçalho Referrer-Policy para controlar quanto informações de referência são enviadas Flight::response()->header('Referrer-Policy', 'no-referrer-when-downgrade'); // Defina o cabeçalho Strict-Transport-Security para forçar HTTPS Flight::response()->header('Strict-Transport-Security', 'max-age=31536000; includeSubDomains; preload'); // Defina o cabeçalho Permissions-Policy para controlar quais recursos e APIs podem ser usados Flight::response()->header('Permissions-Policy', 'geolocation=()');
Esses cabeçalhos podem ser adicionados no início de seus arquivos bootstrap.php ou index.php.
bootstrap.php
index.php
Você também pode adicioná-los em um filtro/gatilho como o seguinte:
// Adicione os cabeçalhos em um filtro Flight::before('start', function() { Flight::response()->header('X-Frame-Options', 'SAMEORIGIN'); Flight::response()->header("Content-Security-Policy", "default-src 'self'"); Flight::response()->header('X-XSS-Protection', '1; mode=block'); Flight::response()->header('X-Content-Type-Options', 'nosniff'); Flight::response()->header('Referrer-Policy', 'no-referrer-when-downgrade'); Flight::response()->header('Strict-Transport-Security', 'max-age=31536000; includeSubDomains; preload'); Flight::response()->header('Permissions-Policy', 'geolocation=()'); });
Você também pode adicioná-los como uma classe de middleware. Esta é uma boa maneira de manter seu código limpo e organizado.
// app/middleware/SecurityHeadersMiddleware.php namespace app\middleware; class SecurityHeadersMiddleware { public function before(array $params): void { Flight::response()->header('X-Frame-Options', 'SAMEORIGIN'); Flight::response()->header("Content-Security-Policy", "default-src 'self'"); Flight::response()->header('X-XSS-Protection', '1; mode=block'); Flight::response()->header('X-Content-Type-Options', 'nosniff'); Flight::response()->header('Referrer-Policy', 'no-referrer-when-downgrade'); Flight::response()->header('Strict-Transport-Security', 'max-age=31536000; includeSubDomains; preload'); Flight::response()->header('Permissions-Policy', 'geolocation=()'); } } // index.php ou onde quer que você tenha suas rotas // FYI, este grupo de string vazia funciona como um middleware global para // todas as rotas. Claro que você também poderia fazer o mesmo e adicionar // isso apenas a rotas específicas. Flight::group('', function(Router $router) { $router->get('/users', [ 'UserController', 'getUsers' ]); // mais rotas }, [ new SecurityHeadersMiddleware() ]);
A Falsificação de Solicitação entre Sites (CSRF) é um tipo de ataque no qual um site malicioso pode fazer com que o navegador de um usuário envie uma solicitação para o seu site. Isso pode ser usado para realizar ações no seu site sem o conhecimento do usuário. Flight não fornece um mecanismo de proteção CSRF integrado, mas você pode implementar facilmente o seu próprio usando middleware.
Primeiro, você precisa gerar um token CSRF e armazená-lo na sessão do usuário. Você pode então usar esse token em seus formulários e verificá-lo quando o formulário for enviado.
// Gere um token CSRF e armazene-o na sessão do usuário // (assumindo que você tenha criado um objeto de sessão e o tenha vinculado ao Flight) // consulte a documentação da sessão para mais informações Flight::register('session', \Ghostff\Session\Session::class); // Você só precisa gerar um token único por sessão (para que funcione // em várias abas e solicitações para o mesmo usuário) if(Flight::session()->get('csrf_token') === null) { Flight::session()->set('csrf_token', bin2hex(random_bytes(32)) ); }
<!-- Use o token CSRF em seu formulário --> <form method="post"> <input type="hidden" name="csrf_token" value="<?= Flight::session()->get('csrf_token') ?>"> <!-- outros campos do formulário --> </form>
Você também pode configurar uma função personalizada para exibir o token CSRF em seus templates Latte.
// Configure uma função personalizada para exibir o token CSRF // Nota: a View foi configurada com Latte como mecanismo de visualização Flight::view()->addFunction('csrf', function() { $csrfToken = Flight::session()->get('csrf_token'); return new \Latte\Runtime\Html('<input type="hidden" name="csrf_token" value="' . $csrfToken . '">'); });
Agora, em seus templates Latte, você pode usar a função csrf() para exibir o token CSRF.
csrf()
<form method="post"> {csrf()} <!-- outros campos do formulário --> </form>
Curto e simples, certo?
Você pode verificar o token CSRF usando filtros de evento:
// Este middleware verifica se a solicitação é uma solicitação POST e, se for, verifica se o token CSRF é válido Flight::before('start', function() { if(Flight::request()->method == 'POST') { // capture o token csrf dos valores do formulário $token = Flight::request()->data->csrf_token; if($token !== Flight::session()->get('csrf_token')) { Flight::halt(403, 'Token CSRF inválido'); // ou para uma resposta JSON Flight::jsonHalt(['error' => 'Token CSRF inválido'], 403); } } });
Ou você pode usar uma classe de middleware:
// app/middleware/CsrfMiddleware.php namespace app\middleware; class CsrfMiddleware { public function before(array $params): void { if(Flight::request()->method == 'POST') { $token = Flight::request()->data->csrf_token; if($token !== Flight::session()->get('csrf_token')) { Flight::halt(403, 'Token CSRF inválido'); } } } } // index.php ou onde quer que você tenha suas rotas Flight::group('', function(Router $router) { $router->get('/users', [ 'UserController', 'getUsers' ]); // mais rotas }, [ new CsrfMiddleware() ]);
A Injeção de Script entre Sites (XSS) é um tipo de ataque no qual um site malicioso pode injetar código em seu site. A maioria dessas oportunidades vem de valores de formulários que seus usuários preencherão. Você nunca deve confiar na saída de seus usuários! Sempre assuma que todos são os melhores hackers do mundo. Eles podem injetar JavaScript ou HTML malicioso em sua página. Esse código pode ser usado para roubar informações de seus usuários ou realizar ações em seu site. Usando a classe de visualização do Flight, você pode escapar facilmente a saída para evitar ataques XSS.
// Vamos assumir que o usuário é inteligente e tenta usar isso como seu nome $nome = '<script>alert("XSS")</script>'; // Isso irá escapar a saída Flight::view()->set('name', $nome); // Isso irá resultar em: <script>alert("XSS")</script> // Se você usar algo como Latte registrado como sua classe de visualização, ele também irá auto escapar isso. Flight::view()->render('template', ['name' => $nome]);
A Injeção de SQL é um tipo de ataque no qual um usuário malicioso pode injetar código SQL em seu banco de dados. Isso pode ser usado para roubar informações do seu banco de dados ou realizar ações no banco de dados. Novamente, você nunca deve confiar na entrada de seus usuários! Sempre assuma que eles estão atrás de você. Você pode usar declarações preparadas em seus objetos PDO para prevenir a injeção de SQL.
PDO
// Assumindo que você tem Flight::db() registrado como seu objeto PDO $declaracao = Flight::db()->prepare('SELECT * FROM users WHERE username = :username'); $declaracao->execute([':username' => $username]); $usuarios = $declaracao->fetchAll(); // Se você usar a classe PdoWrapper, isso pode ser feito facilmente em uma linha $usuarios = Flight::db()->fetchAll('SELECT * FROM users WHERE username = :username', [ 'username' => $username ]); // Você pode fazer a mesma coisa com um objeto PDO com espaços reservados ? $declaracao = Flight::db()->fetchAll('SELECT * FROM users WHERE username = ?', [ $username ]); // Apenas prometa que nunca JAMAIS fará algo assim... $usuarios = Flight::db()->fetchAll("SELECT * FROM users WHERE username = '{$username}' LIMIT 5"); // porque e se $username = "' OR 1=1; -- "; // Depois que a consulta é construída, ela se parece com isso: // SELECT * FROM users WHERE username = '' OU 1=1; -- LIMIT 5 // Parece estranho, mas é uma consulta válida que funcionará. Na verdade, // é um ataque de injeção SQL muito comum que retornará todos os usuários.
O Compartilhamento de Recursos entre Origens (CORS) é um mecanismo que permite que muitos recursos (por exemplo, fontes, JavaScript, etc.) em uma página da web sejam solicitados de outro domínio fora do domínio de onde o recurso se originou. Flight não possui funcionalidade embutida para CORS, mas isso pode ser facilmente tratado com um gancho para ser executado antes que o método Flight::start() seja chamado.
Flight::start()
// app/utils/CorsUtil.php namespace app\utils; class CorsUtil { public function set(array $params): void { $request = Flight::request(); $response = Flight::response(); if ($request->getVar('HTTP_ORIGIN') !== '') { $this->allowOrigins(); $response->header('Access-Control-Allow-Credentials', 'true'); $response->header('Access-Control-Max-Age', '86400'); } if ($request->method === 'OPTIONS') { if ($request->getVar('HTTP_ACCESS_CONTROL_REQUEST_METHOD') !== '') { $response->header( 'Access-Control-Allow-Methods', 'GET, POST, PUT, DELETE, PATCH, OPTIONS, HEAD' ); } if ($request->getVar('HTTP_ACCESS_CONTROL_REQUEST_HEADERS') !== '') { $response->header( "Access-Control-Allow-Headers", $request->getVar('HTTP_ACCESS_CONTROL_REQUEST_HEADERS') ); } $response->status(200); $response->send(); exit; } } private function allowOrigins(): void { // personalize seus hosts permitidos aqui. $permitidos = [ 'capacitor://localhost', 'ionic://localhost', 'http://localhost', 'http://localhost:4200', 'http://localhost:8080', 'http://localhost:8100', ]; $request = Flight::request(); if (in_array($request->getVar('HTTP_ORIGIN'), $permitidos, true) === true) { $resposta = Flight::response(); $resposta->header("Access-Control-Allow-Origin", $request->getVar('HTTP_ORIGIN')); } } } // index.php ou onde quer que você tenha suas rotas $CorsUtil = new CorsUtil(); // Isso precisa ser executado antes de start. Flight::before('start', [ $CorsUtil, 'setupCors' ]);
A segurança é muito importante e é fundamental garantir que suas aplicações web sejam seguras. Flight fornece uma série de recursos para ajudá-lo a proteger suas aplicações web, mas é importante estar sempre vigilante e garantir que você esteja fazendo tudo o que puder para manter os dados de seus usuários seguros. Sempre assuma o pior e nunca confie na entrada de seus usuários. Sempre escape a saída e use declarações preparadas para prevenir a injeção de SQL. Sempre use middleware para proteger suas rotas de ataques CSRF e CORS. Se você fizer todas essas coisas, estará no caminho certo para construir aplicações web seguras.
O Flight permite que você substitua sua funcionalidade padrão para atender às suas próprias necessidades, sem ter que modificar nenhum código.
Por exemplo, quando o Flight não consegue corresponder a uma URL a uma rota, ele invoca o método notFound, que envia uma resposta genérica de HTTP 404. Você pode substituir esse comportamento usando o método map:
HTTP 404
map
Flight::map('notFound', function() { // Exibir página 404 personalizada include 'errors/404.html'; });
O Flight também permite que você substitua componentes principais do framework. Por exemplo, você pode substituir a classe do Roteador padrão pela sua própria classe personalizada:
// Registre sua classe personalizada Flight::register('router', MyRouter::class); // Quando o Flight carrega a instância do Roteador, ele carregará sua classe $myrouter = Flight::router();
Métodos do framework como map e register, no entanto, não podem ser substituídos. Você receberá um erro se tentar fazê-lo.
register
Nota: Quer entender mais sobre roteamento? Confira a página "por que um framework?" para uma explicação mais aprofundada.
O roteamento básico no Flight é feito correspondendo um padrão de URL com uma função de retorno ou um array de uma classe e método.
Flight::route('/', function(){ echo 'olá mundo!'; });
As rotas são correspondidas na ordem em que são definidas. A primeira rota a corresponder a uma solicitação será invocada.
O callback pode ser qualquer objeto que seja chamável. Você pode usar uma função regular:
function hello() { echo 'olá mundo!'; } Flight::route('/', 'hello');
Você também pode usar um método estático de uma classe:
class Greeting { public static function hello() { echo 'olá mundo!'; } } Flight::route('/', [ 'Greeting','hello' ]);
Ou criando um objeto primeiro e depois chamando o método:
// Saudacao.php class Greeting { public function __construct() { $this->name = 'Fulano'; } public function hello() { echo "Olá, {$this->name}!"; } } // index.php $greeting = new Greeting(); Flight::route('/', [ $greeting, 'hello' ]); // Você também pode fazer isso sem criar o objeto primeiro // Nota: Nenhum argumento será injetado no construtor Flight::route('/', [ 'Greeting', 'hello' ]); // Além disso, você pode usar essa sintaxe mais curta Flight::route('/', 'Greeting->hello'); // ou Flight::route('/', Greeting::class.'->hello');
Se você deseja usar injeção de dependência via um container (PSR-11, PHP-DI, Dice, etc), o único tipo de rotas onde isso está disponível é criando o objeto diretamente e usando o container para criar seu objeto ou você pode usar strings para definir a classe e o método a serem chamados. Você pode ir para a página Injeção de Dependência para obter mais informações.
Aqui está um exemplo rápido:
use flight\database\PdoWrapper; // Saudacao.php class Greeting { protected PdoWrapper $pdoWrapper; public function __construct(PdoWrapper $pdoWrapper) { $this->pdoWrapper = $pdoWrapper; } public function hello(int $id) { // faça algo com $this->pdoWrapper $nome = $this->pdoWrapper->fetchField("SELECT nome FROM users WHERE id = ?", [ $id ]); echo "Olá, mundo! Meu nome é {$nome}!"; } } // index.php // Configure o container com os parâmetros de que você precisa // Veja a página de Injeção de Dependência para mais informações sobre PSR-11 $dice = new \Dice\Dice(); // Não se esqueça de reatribuir a variável com '$dice = '!!!!! $dice = $dice->addRule('flight\database\PdoWrapper', [ 'shared' => true, 'constructParams' => [ 'mysql:host=localhost;dbname=test', 'root', 'password' ] ]); // Registre o manipulador do container Flight::registerContainerHandler(function($class, $params) use ($dice) { return $dice->create($class, $params); }); // Rotas como de costume Flight::route('/hello/@id', [ 'Greeting', 'hello' ]); // ou Flight::route('/hello/@id', 'Greeting->hello'); // ou Flight::route('/hello/@id', 'Greeting::hello'); Flight::start();
Por padrão, os padrões de rota são correspondidos a todos os métodos de solicitação. Você pode responder a métodos específicos colocando um identificador antes da URL.
Flight::route('GET /', function () { echo 'Recebi um pedido GET.'; }); Flight::route('POST /', function () { echo 'Recebi um pedido POST.'; }); // Você não pode usar Flight::get() para rotas, pois isso é um método // para obter variáveis, não criar uma rota. // Flight::post('/', function() { /* código */ }); // Flight::patch('/', function() { /* código */ }); // Flight::put('/', function() { /* código */ }); // Flight::delete('/', function() { /* código */ });
Você também pode mapear vários métodos para um único callback usando um delimitador |:
|
Flight::route('GET|POST /', function () { echo 'Recebi um pedido GET ou POST.'; });
Além disso, você pode pegar o objeto Router que possui alguns métodos auxiliares para você usar:
$router = Flight::router(); // mapeia todos os métodos $router->map('/', function() { echo 'olá mundo!'; }); // pedido GET $router->get('/users', function() { echo 'usuários'; }); // $router->post(); // $router->put(); // $router->delete(); // $router->patch();
Você pode usar expressões regulares em suas rotas:
Flight::route('/usuario/[0-9]+', function () { // Isso corresponderá a /usuario/1234 });
Embora este método esteja disponível, é recomendado usar parâmetros nomeados, ou parâmetros nomeados com expressões regulares, pois eles são mais legíveis e mais fáceis de manter.
Você pode especificar parâmetros nomeados em suas rotas que serão passados para sua função de retorno.
Flight::route('/@nome/@id', function (string $nome, string $id) { echo "olá, $nome ($id)!"; });
Você também pode incluir expressões regulares com seus parâmetros nomeados usando o delimitador ::
:
Flight::route('/@nome/@id:[0-9]{3}', function (string $nome, string $id) { // Isso corresponderá a /bob/123 // Mas não corresponderá a /bob/12345 });
Nota: A correspondência de grupos regex () com parâmetros nomeados não é suportada. :'(
()
Você pode especificar parâmetros nomeados que são opcionais para corresponder envolvendo segmentos entre parênteses.
Flight::route( '/blog(/@ano(/@mes(/@dia)))', function(?string $ano, ?string $mes, ?string $dia) { // Isso corresponderá às seguintes URLs: // /blog/2012/12/10 // /blog/2012/12 // /blog/2012 // /blog } );
Quaisquer parâmetros opcionais que não forem correspondidos serão passados como NULL.
NULL
A correspondência é feita apenas em segmentos individuais de URL. Se você deseja corresponder a vários segmentos, você pode usar o curinga *.
*
Flight::route('/blog/*', function () { // Isso corresponderá a /blog/2000/02/01 });
Para rotear todas as solicitações para um único callback, você pode fazer:
Flight::route('*', function () { // Faça algo });
Você pode passar a execução para a próxima rota correspondente retornando true de sua função de retorno.
Flight::route('/usuario/@nome', function (string $nome) { // Verifique alguma condição if ($nome !== "João") { // Continue para a próxima rota return true; } }); Flight::route('/usuario/*', function () { // Isso será chamado });
Você pode atribuir um alias a uma rota, para que a URL possa ser gerada dinamicamente mais tarde em seu código (como em um modelo, por exemplo).
Flight::route('/usuarios/@id', function($id) { echo 'usuário:'.$id; }, false, 'visualizacao_usuario'); // mais tarde em algum lugar do código Flight::getUrl('visualizacao_usuario', [ 'id' => 5 ]); // retornará '/usuarios/5'
Isso é especialmente útil se sua URL mudar. No exemplo acima, digamos que usuários foram movidos para /admin/usuarios/@id ao invés disso. Com o uso de alias, você não precisa alterar em qualquer lugar que faça referência ao alias, porque o alias agora retornará /admin/usuarios/5 como no exemplo acima.
/admin/usuarios/@id
/admin/usuarios/5
O alias de rota ainda funciona em grupos também:
Flight::group('/usuarios', function() { Flight::route('/@id', function($id) { echo 'usuário:'.$id; }, false, 'visualizacao_usuario'); }); // mais tarde em algum lugar do código Flight::getUrl('visualizacao_usuario', [ 'id' => 5 ]); // retornará '/usuarios/5'
Se você quiser inspecionar as informações da rota correspondente, pode solicitar que o objeto da rota seja passado para sua função de retorno passando true como terceiro parâmetro no método de roteamento. O objeto da rota sempre será o último parâmetro passado para sua função de retorno.
Flight::route('/', function(\flight\net\Route $route) { // Array de métodos HTTP correspondentes $route->methods; // Array de parâmetros nomeados $route->params; // Expressão regular correspondente $route->regex; // Contém o conteúdo de qualquer '*' usado no padrão de URL $route->splat; // Mostra o caminho da URL.... se você realmente precisar $route->pattern; // Mostra qual middleware está atribuído a isto $route->middleware; // Mostra o alias atribuído a esta rota $route->alias; }, true);
Pode haver momentos em que você deseja agrupar rotas relacionadas juntas (como /api/v1). Você pode fazer isso usando o método group:
/api/v1
group
Flight::group('/api/v1', function () { Flight::route('/usuarios', function () { // Corresponde a /api/v1/usuarios }); Flight::route('/posts', function () { // Corresponde a /api/v1/posts }); });
Você pode até aninhar grupos de grupos:
Flight::group('/api', function () { Flight::group('/v1', function () { // Flight::get() obtém variáveis, não define uma rota! Veja abaixo o contexto do objeto Flight::route('GET /usuarios', function () { // Corresponde a GET /api/v1/usuarios }); Flight::post('/posts', function () { // Corresponde a POST /api/v1/posts }); Flight::put('/posts/1', function () { // Corresponde a PUT /api/v1/posts }); }); Flight::group('/v2', function () { // Flight::get() obtém variáveis, não define uma rota! Veja abaixo o contexto do objeto Flight::route('GET /usuarios', function () { // Corresponde a GET /api/v2/usuarios }); }); });
Você ainda pode usar o agrupamento de rotas com o objeto Engine da seguinte maneira:
Engine
$app = new \flight\Engine(); $app->group('/api/v1', function (Router $router) { // use a variável $router $router->get('/usuarios', function () { // Corresponde a GET /api/v1/usuarios }); $router->post('/posts', function () { // Corresponde a POST /api/v1/posts }); });
Agora é possível transmitir respostas para o cliente usando o método streamWithHeaders(). Isso é útil para enviar arquivos grandes, processos em execução longa ou gerar respostas grandes. A transmissão de uma rota é tratada de forma um pouco diferente de uma rota regular.
streamWithHeaders()
Nota: A transmissão de respostas só está disponível se você tiver flight.v2.output_buffering configurado como false.
Você pode transmitir uma resposta para o cliente usando o método stream() em uma rota. Se você fizer isso, deve definir todos os métodos manualmente antes de enviar qualquer coisa para o cliente. Isso é feito com a função header() do PHP ou o método Flight::response()->setRealHeader().
stream()
header()
Flight::response()->setRealHeader()
Flight::route('/@nome_arquivo', function($nome_arquivo) { // obviamente você sanitizaria o caminho e tudo o mais. $nomeArquivoSeguro = basename($nome_arquivo); // Se você tiver cabeçalhos adicionais a definir aqui depois que a rota for executada // você deve defini-los antes de qualquer coisa ser ecoada. // Eles devem todos ser chamada direta para a função header() ou // uma chamada para o método Flight::response()->setRealHeader() header('Content-Disposition: attachment; filename="'.$nomeArquivoSeguro.'"'); // ou Flight::response()->setRealHeader('Content-Disposition', 'attachment; filename="'.$nomeArquivoSeguro.'"'); $dadosArquivo = file_get_contents('/algum/caminho/para/arquivos/'.$nomeArquivoSeguro); // Captura de erro e o que mais if(empty($dadosArquivo)) { Flight::halt(404, 'Arquivo não encontrado'); } // defina manualmente o tamanho do conteúdo se desejar header('Content-Length: '.filesize($nome_arquivo)); // Transmita os dados para o cliente echo $dadosArquivo; // Esta é a linha mágica aqui })->stream();
Você também pode usar o método streamWithHeaders() para definir os cabeçalhos antes de começar a transmitir.
Flight::route('/stream-usuarios', function() { // você pode adicionar quaisquer cabeçalhos adicionais que desejar aqui // você só precisa usar header() ou Flight::response()->setRealHeader() // como você puxa seus dados, apenas como exemplo... $usuarios_stmt = Flight::db()->query("SELECT id, nome, sobrenome FROM usuarios"); echo '{'; $contador_usuarios = count($usuarios); while($usuario = $usuarios_stmt->fetch(PDO::FETCH_ASSOC)) { echo json_encode($usuario); if(--$contador_usuarios > 0) { echo ','; } // Isso é necessário para enviar os dados para o cliente ob_flush(); } echo '}'; // É assim que você definirá os cabeçalhos antes de começar a transmitir. })->streamWithHeaders([ 'Content-Type' => 'application/json', 'Content-Disposition' => 'attachment; filename="usuarios.json"', // código de status opcional, padrão é 200 'status' => 200 ]);
Symfony é um conjunto de componentes PHP reutilizáveis e um framework PHP para projetos web.
A base padrão na qual as melhores aplicações PHP são construídas. Escolha qualquer um dos 50 componentes independentes disponíveis para suas próprias aplicações.
Acelere a criação e manutenção de suas aplicações web PHP. Encerre tarefas repetitivas de codificação e aproveite o poder de controlar seu código.
Se você está migrando de outro framework como Laravel, Slim, Fat-Free, ou Symfony para o Flight, esta página irá ajudá-lo a entender as diferenças entre os dois.
Laravel é um framework completo que possui todos os recursos e uma incrível ecossistema focado no desenvolvedor, mas com um custo em desempenho e complexidade.
Veja a comparação entre Laravel e Flight.
Slim é um micro-framework que é semelhante ao Flight. Ele é projetado para ser leve e fácil de usar, mas pode ser um pouco mais complexo do que o Flight.
Veja a comparação entre Slim e Flight.
Fat-Free é um framework full-stack em um pacote muito menor. Embora tenha todas as ferramentas necessárias, ele possui uma arquitetura de dados que pode tornar alguns projetos mais complexos do que precisam ser.
Veja a comparação entre Fat-Free e Flight.
Symfony é um framework modular de nível empresarial projetado para ser flexível e escalável. Para projetos menores ou desenvolvedores mais novos, Symfony pode ser um pouco avassalador.
Veja a comparação entre Symfony e Flight.
Para verificar se uma variável foi definida, você pode fazer:
O Flight também usa variáveis para fins de configuração.
O Contentor de Injeção de Dependência (CID) é uma ferramenta poderosa que permite gerenciar as dependências de sua aplicação. É um conceito-chave nos frameworks PHP modernos e é usado para gerenciar a instanciação e configuração de objetos. Alguns exemplos de bibliotecas CID são: Dice, Pimple, PHP-DI e league/container.
Um CID é uma forma sofisticada de dizer que permite criar e gerenciar suas classes em um local centralizado. Isso é útil quando você precisa passar o mesmo objeto para múltiplas classes (como seus controladores). Um exemplo simples pode ajudar a tornar isso mais claro.
A maneira antiga de fazer as coisas poderia parecer assim:
require 'vendor/autoload.php'; // classe para gerenciar usuários no banco de dados class UserController { protected PDO $pdo; public function __construct(PDO $pdo) { $this->pdo = $pdo; } public function view(int $id) { $stmt = $this->pdo->prepare('SELECT * FROM users WHERE id = :id'); $stmt->execute(['id' => $id]); print_r($stmt->fetch()); } } $User = new UserController(new PDO('mysql:host=localhost;dbname=test', 'user', 'pass')); Flight::route('/user/@id', [ $UserController, 'view' ]); Flight::start();
Você pode ver a partir do código acima que estamos criando um novo objeto PDO e passando-o para nossa classe UserController. Isso é bom para uma aplicação pequena, mas à medida que a aplicação cresce, você descobrirá que está criando o mesmo objeto PDO em múltiplos lugares. É aqui que um CID se torna útil.
UserController
Aqui está o mesmo exemplo usando um CID (usando Dice):
require 'vendor/autoload.php'; // mesma classe que acima. Nada mudou class UserController { protected PDO $pdo; public function __construct(PDO $pdo) { $this->pdo = $pdo; } public function view(int $id) { $stmt = $this->pdo->prepare('SELECT * FROM users WHERE id = :id'); $stmt->execute(['id' => $id]); print_r($stmt->fetch()); } } // criar um novo contentor $container = new \Dice\Dice; // não se esqueça de reatribuí-lo a si mesmo como abaixo! $container = $container->addRule('PDO', [ // shared significa que o mesmo objeto será retornado toda vez 'shared' => true, 'constructParams' => ['mysql:host=localhost;dbname=test', 'user', 'pass' ] ]); // Isso registra o manipulador do contentor para que o Flight saiba usá-lo. Flight::registerContainerHandler(function($class, $params) use ($container) { return $container->create($class, $params); }); // agora podemos usar o contentor para criar nosso UserController Flight::route('/user/@id', [ 'UserController', 'view' ]); // ou alternativamente você pode definir a rota assim Flight::route('/user/@id', 'UserController->view'); // ou Flight::route('/user/@id', 'UserController::view'); Flight::start();
Aposto que você pode estar pensando que houve muito código extra adicionado ao exemplo. A magia acontece quando você tem outro controlador que precisa do objeto PDO.
// Se todos os seus controladores têm um construtor que precisa de um objeto PDO // cada uma das rotas abaixo terá automaticamente ele injetado!!! Flight::route('/empresa/@id', 'CompanyController->view'); Flight::route('/organizacao/@id', 'OrganizationController->view'); Flight::route('/categoria/@id', 'CategoryController->view'); Flight::route('/configuracoes', 'SettingsController->view');
O benefício adicional de utilizar um CID é que os testes unitários se tornam muito mais fáceis. Você pode criar um objeto falso e passá-lo para sua classe. Isso é um grande benefício ao escrever testes para sua aplicação!
O Flight também pode usar qualquer contentor compatível com o PSR-11. Isso significa que você pode usar qualquer contentor que implemente a interface PSR-11. Aqui está um exemplo usando o contentor PSR-11 da League:
require 'vendor/autoload.php'; // mesma classe UserController que acima $container = new \League\Container\Container(); $container->add(UserController::class)->addArgument(PdoWrapper::class); $container->add(PdoWrapper::class) ->addArgument('mysql:host=localhost;dbname=test') ->addArgument('user') ->addArgument('pass'); Flight::registerContainerHandler($container); Flight::route('/user', [ 'UserController', 'view' ]); Flight::start();
Embora isso possa ser um pouco mais verboso do que o exemplo anterior com Dice, ainda faz o trabalho com os mesmos benefícios!
Você também pode criar seu próprio manipulador CID. Isso é útil se você tiver um contentor personalizado que deseja usar que não seja PSR-11 (Dice). Veja o exemplo básico de como fazer isso.
Além disso, existem alguns padrões úteis que facilitarão sua vida ao usar o Flight.
Se você estiver usando a instância Engine em seus controladores/funções intermediárias, aqui está como você configuraria:
// Em algum lugar do seu arquivo de inicialização $engine = Flight::app(); $container = new \Dice\Dice; $container = $container->addRule('*', [ 'substitutions' => [ // Aqui é onde você passa a instância Engine::class => $engine ] ]); $engine->registerContainerHandler(function($class, $params) use ($container) { return $container->create($class, $params); }); // Agora você pode usar a instância do Engine em seus controladores/funções intermediárias class MeuControlador { public function __construct(Engine $app) { $this->app = $app; } public function index() { $this->app->render('index'); } }
Se você tem outras classes que deseja adicionar ao contentor, com Dice é fácil, pois elas serão automaticamente resolvidas pelo contentor. Aqui está um exemplo:
$container = new \Dice\Dice; // Se você não precisa injetar nada em sua classe // você não precisa definir nada! Flight::registerContainerHandler(function($class, $params) use ($container) { return $container->create($class, $params); }); class MinhaClassePersonalizada { public function parseCoisa() { return 'coisa'; } } class UserController { protected MyCustomClass $MyCustomClass; public function __construct(MyCustomClass $MyCustomClass) { $this->MyCustomClass = $MyCustomClass; } public function index() { echo $this->MyCustomClass->parseThing(); } } Flight::route('/user', 'UserController->index');
O Flight suporta middleware de rota e de grupo de rotas. O middleware é uma função que é executada antes (ou depois) do retorno da rota. Esta é uma ótima maneira de adicionar verificações de autenticação da API em seu código, ou para validar se o usuário tem permissão para acessar a rota.
Aqui está um exemplo básico:
// Se você fornecer apenas uma função anônima, ela será executada antes do retorno da rota. // não existem funções de middleware "after" exceto para classes (veja abaixo) Flight::route('/caminho', function() { echo ' Aqui estou!'; })->addMiddleware(function() { echo 'Middleware primeiro!'; }); Flight::start(); // Isso irá produzir "Middleware primeiro! Aqui estou!"
Existem algumas notas muito importantes sobre middleware que você deve ter em mente antes de usá-los:
Flight::redirect()
function($params) { ... }
public function before($params) {}
flight\Engine
__construct()
O middleware pode ser registrado como uma classe também. Se você precisa da funcionalidade "after", você deve usar uma classe.
class MeuMiddleware { public function before($params) { echo 'Middleware primeiro!'; } public function after($params) { echo 'Middleware último!'; } } $MeuMiddleware = new MeuMiddleware(); Flight::route('/caminho', function() { echo ' Aqui estou! '; })->addMiddleware($MeuMiddleware); // também ->addMiddleware([ $MeuMiddleware, $MeuMiddleware2 ]); Flight::start(); // Isso irá exibir "Middleware primeiro! Aqui estou! Middleware último!"
Digamos que você tenha um middleware de autenticação e deseje redirecionar o usuário para uma página de login se ele não estiver autenticado. Você tem algumas opções à sua disposição:
Aqui está um exemplo simples de retorno falso:
class MeuMiddleware { public function before($params) { if (isset($_SESSION['user']) === false) { return false; } // como é verdadeiro, tudo continua normalmente } }
Aqui está um exemplo de redirecionamento do usuário para uma página de login:
class MeuMiddleware { public function before($params) { if (isset($_SESSION['user']) === false) { Flight::redirect('/login'); exit; } } }
Digamos que você precise lançar um erro JSON porque está construindo uma API. Você pode fazer isso assim:
class MeuMiddleware { public function before($params) { $autorizacao = Flight::request()->headers['Authorization']; if(empty($autorizacao)) { Flight::jsonHalt(['error' => 'Você deve estar logado para acessar esta página.'], 403); // ou Flight::json(['error' => 'Você deve estar logado para acessar esta página.'], 403); exit; // ou Flight::halt(403, json_encode(['error' => 'Você deve estar logado para acessar esta página.']); } } }
Você pode adicionar um grupo de rota e, em seguida, cada rota nesse grupo terá o mesmo middleware também. Isso é útil se você precisar agrupar um monte de rotas, digamos por um middleware de Autenticação para verificar a chave da API no cabeçalho.
// adicionado no final do método de grupo Flight::group('/api', function() { // Esta rota com aparência "vazia" na verdade corresponderá a /api Flight::route('', function() { echo 'api'; }, false, 'api'); // Esta corresponderá a /api/usuarios Flight::route('/usuarios', function() { echo 'usuários'; }, false, 'usuários'); // Esta corresponderá a /api/usuarios/1234 Flight::route('/usuarios/@id', function($id) { echo 'usuário:'.$id; }, false, 'visualização_de_usuario'); }, [ new MiddlewaredeAutenticacaoApi() ]);
Se você deseja aplicar um middleware global a todas as suas rotas, pode adicionar um grupo "vazio":
// adicionado no final do método de grupo Flight::group('', function() { // Isto ainda é /usuários Flight::route('/usuários', function() { echo 'usuários'; }, false, 'usuários'); // E isto ainda é /usuários/1234 Flight::route('/usuários/@id', function($id) { echo 'usuário:'.$id; }, false, 'visualização_de_usuario'); }, [ new MiddlewaredeAutenticacaoApi() ]);
O Flight permite que você filtre métodos antes e depois de serem chamados. Não há ganchos predefinidos que você precise memorizar. Você pode filtrar qualquer um dos métodos padrão do framework, bem como quaisquer métodos personalizados que você tenha mapeado.
Uma função de filtro parece com isso:
function (array &$params, string &$output): bool { // Código do filtro }
Usando as variáveis passadas, você pode manipular os parâmetros de entrada e/ou a saída.
Você pode ter um filtro sendo executado antes de um método fazendo:
Flight::before('start', function (array &$params, string &$output): bool { // Faça algo });
Você pode ter um filtro sendo executado após um método fazendo:
Flight::after('start', function (array &$params, string &$output): bool { // Faça algo });
Você pode adicionar quantos filtros quiser a qualquer método. Eles serão chamados na ordem em que são declarados.
Aqui está um exemplo do processo de filtragem:
// Mapeie um método personalizado Flight::map('hello', function (string $name) { return "Olá, $name!"; }); // Adicione um filtro antes Flight::before('hello', function (array &$params, string &$output): bool { // Manipule o parâmetro $params[0] = 'Fred'; return true; }); // Adicione um filtro após Flight::after('hello', function (array &$params, string &$output): bool { // Manipule a saída $output .= " Tenha um bom dia!"; return true; }); // Invoque o método personalizado echo Flight::hello('Bob');
Isso deve exibir:
Olá Fred! Tenha um bom dia!
Se você definiu vários filtros, você pode interromper a cadeia retornando false em qualquer uma de suas funções de filtro:
false
Flight::before('start', function (array &$params, string &$output): bool { echo 'um'; return true; }); Flight::before('start', function (array &$params, string &$output): bool { echo 'dois'; // Isso irá encerrar a cadeia return false; }); // Isso não será chamado Flight::before('start', function (array &$params, string &$output): bool { echo 'três'; return true; });
Observação, métodos principais como map e register não podem ser filtrados porque são chamados diretamente e não invocados dinamicamente.
Flight encapsula a requisição HTTP em um único objeto, que pode ser acessado fazendo:
$request = Flight::request();
Quando você está trabalhando com uma requisição em uma aplicação web, tipicamente você vai querer extrair um cabeçalho, ou um parâmetro $_GET ou $_POST, ou talvez até mesmo o corpo bruto da requisição. Flight fornece uma interface simples para fazer todas essas coisas.
$_GET
$_POST
Aqui está um exemplo obtendo um parâmetro de string de consulta:
Flight::route('/search', function(){ $keyword = Flight::request()->query['keyword']; echo "Você está pesquisando por: $keyword"; // consultar um banco de dados ou algo assim com o $keyword });
Aqui está um exemplo de talvez um formulário com um método POST:
Flight::route('POST /submit', function(){ $name = Flight::request()->data['name']; $email = Flight::request()->data['email']; echo "Você enviou: $name, $email"; // salvar em um banco de dados ou algo assim com o $name e $email });
O objeto de requisição fornece as seguintes propriedades:
$_SERVER
HTTP_CLIENT_IP
HTTP_X_FORWARDED_FOR
HTTP_X_FORWARDED
HTTP_X_CLUSTER_CLIENT_IP
HTTP_FORWARDED_FOR
HTTP_FORWARDED
Você pode acessar as propriedades query, data, cookies e files como arrays ou objetos.
query
data
cookies
files
Então, para obter um parâmetro de string de consulta, você pode fazer:
$id = Flight::request()->query['id'];
Ou você pode fazer:
$id = Flight::request()->query->id;
Para obter o corpo bruto da requisição HTTP, por exemplo, ao lidar com requisições PUT, você pode fazer:
$body = Flight::request()->getBody();
Se você enviar uma requisição com o tipo application/json e os dados {"id": 123} eles estarão disponíveis na propriedade data:
application/json
{"id": 123}
$id = Flight::request()->data->id;
Você pode acessar o array $_GET através da propriedade query:
Você pode acessar o array $_POST através da propriedade data:
$id = Flight::request()->data['id'];
$_COOKIE
Você pode acessar o array $_COOKIE através da propriedade cookies:
$myCookieValue = Flight::request()->cookies['myCookieName'];
Há um atalho disponível para acessar o array $_SERVER através do método getVar():
getVar()
$host = Flight::request()->getVar['HTTP_HOST'];
$_FILES
Você pode acessar arquivos enviados através da propriedade files:
$uploadedFile = Flight::request()->files['myFile'];
Você pode processar o envio de arquivos usando o framework com alguns métodos auxiliares. Basicamente resume-se a puxar os dados do arquivo da requisição e movê-los para um novo local.
Flight::route('POST /upload', function(){ // Se você tiver um campo de entrada como <input type="file" name="myFile"> $uploadedFileData = Flight::request()->getUploadedFiles(); $uploadedFile = $uploadedFileData['myFile']; $uploadedFile->moveTo('/caminho/para/uploads/' . $uploadedFile->getClientFilename()); });
Se você tiver vários arquivos enviados, você pode percorrê-los:
Flight::route('POST /upload', function(){ // Se você tiver um campo de entrada como <input type="file" name="myFiles[]"> $uploadedFiles = Flight::request()->getUploadedFiles()['myFiles']; foreach ($uploadedFiles as $uploadedFile) { $uploadedFile->moveTo('/caminho/para/uploads/' . $uploadedFile->getClientFilename()); } });
Nota de Segurança: Sempre valide e sanitize a entrada do usuário, especialmente ao lidar com envios de arquivos. Sempre valide o tipo de extensões que você permitirá que sejam enviadas, mas você também deve validar os "bytes mágicos" do arquivo para garantir que ele é realmente do tipo de arquivo que o usuário afirma que é. Existem artigos e bibliotecas disponíveis para ajudar com isso.
Você pode acessar os cabeçalhos da requisição usando o método getHeader() ou getHeaders():
getHeader()
getHeaders()
// Talvez você precise do cabeçalho Authorization $host = Flight::request()->getHeader('Authorization'); // ou $host = Flight::request()->header('Authorization'); // Se você precisar obter todos os cabeçalhos $headers = Flight::request()->getHeaders(); // ou $headers = Flight::request()->headers();
Você pode acessar o corpo bruto da requisição usando o método getBody():
getBody()
Você pode acessar o método da requisição usando a propriedade method ou o método getMethod():
method
getMethod()
$method = Flight::request()->method; // na verdade chama getMethod() $method = Flight::request()->getMethod();
Nota: O método getMethod() primeiro puxa o método de $_SERVER['REQUEST_METHOD'], depois pode ser substituído por $_SERVER['HTTP_X_HTTP_METHOD_OVERRIDE'] se existir ou $_REQUEST['_method'] se existir.
$_SERVER['REQUEST_METHOD']
$_SERVER['HTTP_X_HTTP_METHOD_OVERRIDE']
$_REQUEST['_method']
Há alguns métodos auxiliares para juntar partes de uma URL para sua conveniência.
Você pode acessar a URL completa da requisição usando o método getFullUrl():
getFullUrl()
$url = Flight::request()->getFullUrl(); // https://example.com/some/path?foo=bar
Você pode acessar a URL base usando o método getBaseUrl():
getBaseUrl()
$url = Flight::request()->getBaseUrl(); // Aviso, sem barra final. // https://example.com
Você pode passar uma URL para o método parseQuery() para analisar a string de consulta em um array associativo:
parseQuery()
$query = Flight::request()->parseQuery('https://example.com/some/path?foo=bar'); // ['foo' => 'bar']
# Métodos do Framework Flight é projetado para ser fácil de usar e entender. O seguinte é o conjunto completo de métodos para o framework. Consiste em métodos principais, que são métodos estáticos regulares, e métodos extensíveis, que são métodos mapeados que podem ser filtrados ou substituídos. ## Métodos Principais ```php Flight::map(string $name, callable $callback, bool $pass_route = false) // Cria um método de framework personalizado. Flight::register(string $name, string $class, array $params = [], ?callable $callback = null) // Registra uma classe a um método de framework. Flight::before(string $name, callable $callback) // Adiciona um filtro antes de um método de framework. Flight::after(string $name, callable $callback) // Adiciona um filtro após um método de framework. Flight::path(string $path) // Adiciona um caminho para carregar classes automaticamente. Flight::get(string $key) // Obtém uma variável. Flight::set(string $key, mixed $value) // Define uma variável. Flight::has(string $key) // Verifica se uma variável está definida. Flight::clear(array|string $key = []) // Limpa uma variável. Flight::init() // Inicializa o framework com suas configurações padrão. Flight::app() // Obtém a instância do objeto de aplicativo
Flight::start() // Inicia o framework. Flight::stop() // Para o framework e envia uma resposta. Flight::halt(int $code = 200, string $message = '') // Para o framework com um código de status e mensagem opcionais. Flight::route(string $pattern, callable $callback, bool $pass_route = false) // Mapeia um padrão de URL para um retorno de chamada. Flight::group(string $pattern, callable $callback) // Cria agrupamento para urls, o padrão deve ser uma string. Flight::redirect(string $url, int $code) // Redireciona para outra URL. Flight::render(string $file, array $data, ?string $key = null) // Renderiza um arquivo de modelo. Flight::error(Throwable $error) // Envia uma resposta HTTP 500. Flight::notFound() // Envia uma resposta HTTP 404. Flight::etag(string $id, string $type = 'string') // Realiza o cache do HTTP ETag. Flight::lastModified(int $time) // Realiza o cache do HTTP de última modificação. Flight::json(mixed $data, int $code = 200, bool $encode = true, string $charset = 'utf8', int $option) // Envia uma resposta JSON. Flight::jsonp(mixed $data, string $param = 'jsonp', int $code = 200, bool $encode = true, string $charset = 'utf8', int $option) // Envia uma resposta JSONP.
Quaisquer métodos personalizados adicionados com map e register também podem ser filtrados.
Flight foi projetado para ser fácil de usar e entender. A seguir está o conjunto completo de métodos para o framework. Ele consiste em métodos principais, que são métodos estáticos regulares, e métodos extensíveis, que são métodos mapeados que podem ser filtrados ou anulados.
Estes métodos são essenciais para o framework e não podem ser anulados.
Flight::map(string $nome, callable $retorno, bool $pass_route = false) // Cria um método personalizado para o framework. Flight::register(string $nome, string $classe, array $params = [], ?callable $retorno = null) // Registra uma classe para um método do framework. Flight::unregister(string $nome) // Anula uma classe de um método do framework. Flight::before(string $nome, callable $retorno) // Adiciona um filtro antes de um método do framework. Flight::after(string $nome, callable $retorno) // Adiciona um filtro após um método do framework. Flight::path(string $caminho) // Adiciona um caminho para o carregamento automático de classes. Flight::get(string $chave) // Obtém uma variável definida por Flight::set(). Flight::set(string $chave, mixed $valor) // Define uma variável dentro do mecanismo do Flight. Flight::has(string $chave) // Verifica se uma variável está definida. Flight::clear(array|string $chave = []) // Limpa uma variável. Flight::init() // Inicializa o framework com as configurações padrão. Flight::app() // Obtém a instância do objeto de aplicativo Flight::request() // Obtém a instância do objeto de solicitação Flight::response() // Obtém a instância do objeto de resposta Flight::router() // Obtém a instância do objeto de roteador Flight::view() // Obtém a instância do objeto de visualização
Flight::start() // Inicia o framework. Flight::stop() // Interrompe o framework e envia uma resposta. Flight::halt(int $code = 200, string $message = '') // Interrompe o framework com um código de status e mensagem opcional. Flight::route(string $padrão, callable $retorno, bool $pass_route = false, string $alias = '') // Mapeia um padrão de URL para um retorno. Flight::post(string $padrão, callable $retorno, bool $pass_route = false, string $alias = '') // Mapeia um padrão de URL de solicitação POST para um retorno. Flight::put(string $padrão, callable $retorno, bool $pass_route = false, string $alias = '') // Mapeia um padrão de URL de solicitação PUT para um retorno. Flight::patch(string $padrão, callable $retorno, bool $pass_route = false, string $alias = '') // Mapeia um padrão de URL de solicitação PATCH para um retorno. Flight::delete(string $padrão, callable $retorno, bool $pass_route = false, string $alias = '') // Mapeia um padrão de URL de solicitação DELETE para um retorno. Flight::group(string $padrão, callable $retorno) // Cria agrupamento para URLs, o padrão deve ser uma string. Flight::getUrl(string $nome, array $params = []) // Gera uma URL com base em um alias de rota. Flight::redirect(string $url, int $code) // Redireciona para outra URL. Flight::download(string $caminhoArquivo) // Faz o download de um arquivo. Flight::render(string $arquivo, array $dados, ?string $chave = null) // Renderiza um arquivo de modelo. Flight::error(Throwable $erro) // Envia uma resposta HTTP 500. Flight::notFound() // Envia uma resposta HTTP 404. Flight::etag(string $id, string $tipo = 'string') // Executa o cacheamento HTTP ETag. Flight::lastModified(int $tempo) // Executa o cacheamento HTTP da última modificação. Flight::json(mixed $dados, int $code = 200, bool $encode = true, string $charset = 'utf8', int $opção) // Envia uma resposta JSON. Flight::jsonp(mixed $dados, string $param = 'jsonp', int $code = 200, bool $encode = true, string $charset = 'utf8', int $opção) // Envia uma resposta JSONP. Flight::jsonHalt(mixed $dados, int $code = 200, bool $encode = true, string $charset = 'utf8', int $opção) // Envia uma resposta JSON e interrompe o framework.
Quaisquer métodos personalizados adicionados com map e register também podem ser filtrados. Para exemplos de como mapear esses métodos, consulte o guia Estendendo o Flight.
Alguns programadores são veementemente contra o uso de frameworks. Eles argumentam que os frameworks são inflados, lentos e difíceis de aprender. Dizem que os frameworks são desnecessários e que você pode escrever um código melhor sem eles. Certamente, há alguns pontos válidos a serem considerados sobre as desvantagens do uso de frameworks. No entanto, também existem muitas vantagens em usar frameworks.
Aqui estão algumas razões pelas quais você pode querer considerar o uso de um framework:
Flight é um micro-framework. Isso significa que ele é pequeno e leve. Ele não fornece tanta funcionalidade quanto frameworks maiores como Laravel ou Symfony. No entanto, ele fornece muita da funcionalidade necessária para construir aplicações web. É também fácil de aprender e usar. Isso o torna uma boa escolha para construir aplicações web rapidamente e facilmente. Se você é novo em frameworks, o Flight é um ótimo framework para iniciantes a começar. Vai ajudá-lo a entender as vantagens de usar frameworks sem sobrecarregá-lo com muita complexidade. Depois de adquirir alguma experiência com o Flight, será mais fácil passar para frameworks mais complexos como Laravel ou Symfony, no entanto, o Flight ainda pode criar um aplicativo robusto e bem-sucedido.
O roteamento é o núcleo do framework Flight, mas o que é exatamente? Roteamento é o processo de pegar uma URL e correspondê-la a uma função específica em seu código. É assim que você pode fazer seu site fazer coisas diferentes com base na URL solicitada. Por exemplo, você pode querer mostrar o perfil de um usuário quando ele visita /user/1234, mas mostrar uma lista de todos os usuários quando eles visitam /users. Tudo isso é feito por meio do roteamento.
/user/1234
/users
Pode funcionar algo assim:
http://exemplo.com/user/1234
Flight::route('/user/@id', [ 'ControladorDeUsuario', 'verPerfilDoUsuario' ]);
verPerfilDoUsuario($id)
ControladorDeUsuario
1234
$id
verPerfilDoUsuario()
Ter um roteador centralizado apropriado pode realmente tornar sua vida dramaticamente mais fácil! Pode ser difícil ver isso à primeira vista. Aqui estão algumas razões:
user_view
id
/admin/user/1234
Tenho certeza de que você está familiarizado com a maneira script por script de criar um site. Você pode ter um arquivo chamado index.php que possui um monte de declarações if para verificar a URL e em seguida executar uma função específica com base na URL. Isso é uma forma de roteamento, mas não é muito organizado e pode sair do controle rapidamente. O sistema de roteamento do Flight é uma maneira muito mais organizada e poderosa de lidar com o roteamento.
if
Isto?
// /user/view_profile.php?id=1234 if ($_GET['id']) { $id = $_GET['id']; viewUserProfile($id); } // /user/edit_profile.php?id=1234 if ($_GET['id']) { $id = $_GET['id']; editUserProfile($id); } // etc...
Ou isso?
// index.php Flight::route('/user/@id', [ 'ControladorDeUsuario', 'verPerfilDoUsuario' ]); Flight::route('/user/@id/edit', [ 'ControladorDeUsuario', 'editarPerfilDoUsuario' ]); // Em talvez o seu app/controllers/ControladorDeUsuario.php class ControladorDeUsuario { public function verPerfilDoUsuario($id) { // faça algo } public function editarPerfilDoUsuario($id) { // faça algo } }
Espero que você comece a ver os benefícios de usar um sistema de roteamento centralizado. É muito mais fácil de gerenciar e entender a longo prazo!
O Flight oferece uma maneira simples e fácil de lidar com solicitações e respostas. Este é o núcleo do que um framework web faz. Ele recebe uma solicitação de um navegador de um usuário, a processa e envia de volta uma resposta. Com isso, você pode construir aplicações web que realizem tarefas como mostrar o perfil de um usuário, permitir que um usuário faça login, ou permitir que um usuário poste uma nova postagem em um blog.
Uma solicitação é o que o navegador de um usuário envia para o seu servidor quando eles visitam o seu site. Esta solicitação contém informações sobre o que o usuário quer fazer. Por exemplo, ela pode conter informações sobre qual URL o usuário deseja visitar, quais dados o usuário deseja enviar para o seu servidor, ou que tipo de dados o usuário deseja receber do seu servidor. É importante saber que uma solicitação é somente leitura. Você não pode alterar a solicitação, mas pode lê-la.
O Flight fornece uma maneira simples de acessar informações sobre a solicitação. Você pode acessar informações sobre a solicitação usando o método Flight::request(). Este método retorna um objeto Request que contém informações sobre a solicitação. Você pode usar esse objeto para acessar informações sobre a solicitação, como a URL, o método, ou os dados que o usuário enviou para o seu servidor.
Flight::request()
Request
Uma resposta é o que o seu servidor envia de volta para o navegador de um usuário quando eles visitam o seu site. Esta resposta contém informações sobre o que o seu servidor quer fazer. Por exemplo, ela pode conter informações sobre que tipo de dados o seu servidor quer enviar para o usuário, que tipo de dados seu servidor quer receber do usuário, ou que tipo de dados seu servidor quer armazenar no computador do usuário.
O Flight fornece uma maneira simples de enviar uma resposta para o navegador do usuário. Você pode enviar uma resposta usando o método Flight::response(). Este método recebe um objeto Response como argumento e envia a resposta para o navegador do usuário. Você pode usar este objeto para enviar uma resposta para o navegador do usuário, como HTML, JSON, ou um arquivo. O Flight ajuda a gerar automaticamente algumas partes da resposta para facilitar as coisas, mas, em última instância, você tem controle sobre o que enviar de volta para o usuário.
Flight::response()
Response
Voo fornece suporte embutido para o caching de nível HTTP. Se a condição de caching for atendida, Voo retornará uma resposta 304 Not Modified HTTP. Da próxima vez que o cliente solicitar o mesmo recurso, eles serão convidados a usar sua versão em cache localmente.
304 Not Modified
Você pode usar o método lastModified e passar um carimbo de data/hora UNIX para definir a data e hora em que a página foi modificada pela última vez. O cliente continuará a usar seu cache até que o valor da última modificação seja alterado.
lastModified
Flight::route('/noticias', function () { Flight::lastModified(1234567890); echo 'Este conteúdo será armazenado em cache.'; });
O caching ETag é semelhante ao Última Modificação, exceto que você pode especificar qualquer ID que desejar para o recurso:
ETag
Última Modificação
Flight::route('/noticias', function () { Flight::etag('meu-id-único'); echo 'Este conteúdo será armazenado em cache.'; });
Tenha em mente que chamar lastModified ou etag definirá e verificará o valor do cache. Se o valor do cache for o mesmo entre as solicitações, Voo enviará imediatamente uma resposta HTTP 304 e interromperá o processamento.
etag
HTTP 304
O Flight ajuda a gerar parte dos cabeçalhos de resposta para você, mas você tem a maior parte do controle sobre o que envia de volta para o usuário. Às vezes você pode acessar o objeto Response diretamente, mas na maioria das vezes você usará a instância Flight para enviar uma resposta.
Flight
O Flight usa ob_start() para armazenar em buffer a saída. Isso significa que você pode usar echo ou print para enviar uma resposta ao usuário e o Flight irá capturá-la e enviá-la de volta ao usuário com os cabeçalhos apropriados.
echo
print
// Isto enviará "Olá, Mundo!" para o navegador do usuário Flight::route('/', function() { echo "Olá, Mundo!"; }); // HTTP/1.1 200 OK // Content-Type: text/html // // Olá, Mundo!
Como alternativa, você pode chamar o método write() para adicionar ao corpo também.
write()
// Isto enviará "Olá, Mundo!" para o navegador do usuário Flight::route('/', function() { // verboso, mas resolve o problema às vezes quando você precisa Flight::response()->write("Olá, Mundo!"); // se você quiser recuperar o corpo que definiu neste ponto // você pode fazer assim $body = Flight::response()->getBody(); });
Você pode definir o código de status da resposta usando o método status:
status
Flight::route('/@id', function($id) { if($id == 123) { Flight::response()->status(200); echo "Olá, Mundo!"; } else { Flight::response()->status(403); echo "Proibido"; } });
Se quiser obter o código de status atual, pode usar o método status sem nenhum argumento:
Flight::response()->status(); // 200
Você pode definir o corpo da resposta usando o método write, no entanto, se você usar echo ou print em qualquer coisa, será capturado e enviado como o corpo de resposta via armazenamento em buffer de saída.
write
Flight::route('/', function() { Flight::response()->write("Olá, Mundo!"); }); // mesmo que Flight::route('/', function() { echo "Olá, Mundo!"; });
Se quiser limpar o corpo da resposta, pode usar o método clearBody:
clearBody
Flight::route('/', function() { if($algumaCondicao) { Flight::response()->write("Olá, Mundo!"); } else { Flight::response()->clearBody(); } });
Você pode executar um callback no corpo de resposta usando o método addResponseBodyCallback:
addResponseBodyCallback
Flight::route('/usuarios', function() { $bd = Flight::bd(); $usuarios = $bd->fetchAll("SELECIONAR * FROM usuarios"); Flight::render('tabela_usuarios', ['usuarios' => $usuarios]); }); // Isto irá compactar todas as respostas para qualquer rota Flight::response()->addResponseBodyCallback(function($corpo) { return gzencode($corpo, 9); });
Você pode adicionar vários callbacks e eles serão executados na ordem em que foram adicionados. Porque isso pode aceitar qualquer chamável, pode aceitar um array de classe [ $classe, 'método' ], um fechamento $strReplace = function($corpo) { str_replace('oi', 'olá', $corpo); };, ou um nome de função 'minify' se você tiver uma função para minificar seu código html, por exemplo.
[ $classe, 'método' ]
$strReplace = function($corpo) { str_replace('oi', 'olá', $corpo); };
'minify'
Nota: Os callbacks de rota não funcionarão se você estiver usando a opção de configuração flight.v2.output_buffering.
Se desejar que isso se aplique apenas a uma rota específica, poderá adicionar o callback na própria rota:
Flight::route('/usuarios', function() { $bd = Flight::bd(); $usuarios = $bd->fetchAll("SELECIONAR * FROM usuarios"); Flight::render('tabela_usuarios', ['usuarios' => $usuarios]); // Isto compactará apenas a resposta para esta rota Flight::response()->addResponseBodyCallback(function($corpo) { return gzencode($corpo, 9); }); });
Você também pode usar middleware para aplicar o callback a todas as rotas via middleware:
// MinifyMiddleware.php class MinifyMiddleware { public function before() { // Aplique o callback aqui no objeto response(). Flight::response()->addResponseBodyCallback(function($corpo) { return $this->minify($corpo); }); } protected function minify(string $corpo): string { // minimize o corpo de alguma forma return $corpo; } } // index.php Flight::group('/usuarios', function() { Flight::route('', function() { /* ... */ }); Flight::route('/@id', function($id) { /* ... */ }); }, [ new MinifyMiddleware() ]);
Você pode configurar um cabeçalho, como o tipo de conteúdo da resposta, usando o método header:
// Isto enviará "Olá, Mundo!" para o navegador do usuário em texto simples Flight::route('/', function() { Flight::response()->header('Content-Type', 'text/plain'); // ou Flight::response()->setHeader('Content-Type', 'text/plain'); echo "Olá, Mundo!"; });
O Flight fornece suporte para envio de respostas JSON e JSONP. Para enviar uma resposta JSON você passa alguns dados para serem codificados em JSON:
Flight::json(['id' => 123]);
Você também pode passar um código de status como segundo argumento:
Flight::json(['id' => 123], 201);
Você também pode passar um argumento na última posição para habilitar a impressão bonita:
Flight::json(['id' => 123], 200, true, 'utf-8', JSON_PRETTY_PRINT);
Se estiver alterando as opções passadas para Flight::json() e desejar uma sintaxe mais simples, pode remapear o método JSON:
Flight::json()
Flight::map('json', function($dados, $código = 200, $opções = 0) { Flight::_json($dados, $código, true, 'utf-8', $opções); } // E agora pode ser usado assim Flight::json(['id' => 123], 200, JSON_PRETTY_PRINT);
Se desejar enviar uma resposta JSON e interromper a execução, pode usar o método jsonHalt. Isso é útil para casos em que você está verificando talvez algum tipo de autorização e se o usuário não estiver autorizado, você pode enviar imediatamente uma resposta JSON, limpar o conteúdo do corpo existente e interromper a execução.
jsonHalt
Flight::route('/usuarios', function() { $autorizado = algumaVerificaçãoDeAutorização(); // Verifique se o usuário está autorizado if($autorizado === falso) { Flight::jsonHalt(['erro' => 'Não autorizado'], 401); } // Continue com o restante da rota });
Antes da v3.10.0, você teria que fazer algo assim:
Flight::route('/usuarios', function() { $autorizado = algumaVerificaçãoDeAutorização(); // Verifique se o usuário está autorizado if($autorizado === falso) { Flight::haltar(401, json_encode(['erro' => 'Não autorizado'])); } // Continue com o restante da rota });
Para requisições JSONP, você pode opcionalmente passar o nome do parâmetro da query que você está usando para definir sua função de retorno de chamada:
Flight::jsonp(['id' => 123], 'q');
Portanto, ao fazer uma solicitação GET usando ?q=my_func, você deverá receber a saída:
?q=my_func
my_func({"id":123});
Se você não passar um nome de parâmetro de query, ele será padrão para jsonp.
jsonp
Você pode redirecionar a solicitação atual usando o método redirect() e passando uma nova URL:
Flight::redirect('/nova/localização');
Por padrão, o Flight enviará um código de status HTTP 303 ("See Other"). Você pode opcionalmente definir um código personalizado:
Flight::redirect('/nova/localização', 401);
Você também pode especificar um código de HTTP opcional e mensagem:
Flight::halt(200, 'Já volto...');
Chamar halt descartará qualquer conteúdo de resposta até esse ponto. Se quiser parar o framework e enviar a resposta atual, use o método stop:
Você pode limpar o corpo e os cabeçalhos da resposta usando o método clear(). Isto limpará quaisquer cabeçalhos atribuídos à resposta, limpará o corpo da resposta e definirá o código de status para 200.
clear()
200
Flight::response()->clear();
Se quiser limpar apenas o corpo da resposta, pode usar o método clearBody():
clearBody()
// Isto ainda manterá quaisquer cabeçalhos definidos no objeto response(). Flight::response()->clearBody();
O Flight fornece suporte embutido para caching a nível HTTP. Se a condição de cache for atendida, o Flight retornará uma resposta HTTP 304 Not Modified. Da próxima vez que o cliente solicitar o mesmo recurso, será solicitado a usar sua versão em cache local.
Se desejar armazenar em cache toda a sua resposta, pode usar o método cache() e passar o tempo de cacheamento.
cache()
// Isto vai armazenar em cache a resposta por 5 minutos Flight::route('/notícias', function () { Flight::response()->cache(time() + 300); echo 'Este conteúdo será armazenado em cache.'; }); // Alternativamente, você pode usar uma string que passaria // para o método strtotime() Flight::route('/notícias', function () { Flight::response()->cache('+5 minutos'); echo 'Este conteúdo será armazenado em cache.'; });
Você pode usar o método lastModified e passar um carimbo de data UNIX para definir a data e hora em que uma página foi modificada pela última vez. O cliente continuará usando seu cache até o valor da última modificação ser alterado.
Flight::route('/notícias', function () { Flight::lastModified(1234567890); echo 'Este conteúdo será armazenado em cache.'; });
O cache do ETag é semelhante ao Última Modificação, exceto que você pode especificar qualquer identificador desejado para o recurso:
Flight::route('/notícias', function () { Flight::etag('meu-id-único'); echo 'Este conteúdo será armazenado em cache.'; });
Lembre-se que chamar lastModified ou etag definirá e verificará o valor em cache. Se o valor em cache for o mesmo entre as solicitações, o Flight enviará imediatamente uma resposta HTTP 304 e interromperá o processamento.
Há um método auxiliar para baixar um arquivo. Você pode usar o método download e passar o caminho.
download
Flight::route('/baixar', function () { Flight::download('/caminho/para/arquivo.txt'); });
Em vez de executar o Flight como uma classe estática global, você pode executá-lo opcionalmente como uma instância de objeto.
require 'flight/autoload.php'; $app = Flight::app(); $app->route('/', function () { echo 'olá mundo!'; }); $app->start();
Portanto, em vez de chamar o método estático, você chamaria o método de instância com o mesmo nome no objeto Engine.
Você pode redirecionar a solicitação atual usando o método redirect e passando uma nova URL:
redirect
Flight::redirect('/novo/local');
Por padrão, o Flight envia um código de status HTTP 303. Você pode opcionalmente definir um código personalizado:
Flight::redirect('/novo/local', 401);
Flight fornece alguma funcionalidade básica de modelagem por padrão. Para exibir uma vista chame o método render com o nome do arquivo de modelo e dados de modelo opcionais:
render
Flight::render('hello.php', ['name' => 'Bob']);
Os dados do modelo que você passa são automaticamente injetados no modelo e podem ser referenciados como uma variável local. Os arquivos de modelo são simplesmente arquivos PHP. Se o conteúdo do arquivo de modelo hello.php for:
hello.php
Olá, <?= $name ?>!
A saída seria:
Olá, Bob!
Você também pode definir manualmente variáveis de visualização usando o método set:
Flight::view()->set('name', 'Bob');
A variável name agora está disponível em todas as suas visualizações. Então você pode simplesmente fazer:
name
Flight::render('hello');
Observe que ao especificar o nome do modelo no método render, você pode omitir a extensão .php.
.php
Por padrão, o Flight procurará um diretório views para arquivos de modelo. Você pode definir um caminho alternativo para seus modelos configurando o seguinte:
views
Flight::set('flight.views.path', '/caminho/para/views');
É comum que sites tenham um único arquivo de modelo de layout com conteúdo alternante. Para renderizar conteúdo a ser usado em um layout, você pode passar um parâmetro opcional para o método render.
Flight::render('header', ['heading' => 'Olá'], 'headerContent'); Flight::render('body', ['body' => 'Mundo'], 'bodyContent');
Sua visualização então terá variáveis salvas chamadas headerContent e bodyContent. Você pode então renderizar seu layout fazendo:
headerContent
bodyContent
Flight::render('layout', ['title' => 'Página Inicial']);
Se os arquivos de modelo forem assim:
header.php:
header.php
<h1><?= $heading ?></h1>
body.php:
body.php
<div><?= $body ?></div>
layout.php:
layout.php
<html> <head> <title><?= $title ?></title> </head> <body> <?= $headerContent ?> <?= $bodyContent ?> </body> </html>
<html> <head> <title>Página Inicial</title> </head> <body> <h1>Olá</h1> <div>Mundo</div> </body> </html>
O Flight permite que você substitua a engine de visualização padrão simplesmente registrando sua própria classe de visualização. Veja como você usaria o Smarty template engine para suas visualizações:
// Carregar biblioteca do Smarty require './Smarty/libs/Smarty.class.php'; // Registrar Smarty como a classe de visualização // Também passar uma função de retorno de chamada para configurar o Smarty ao carregar Flight::register('view', Smarty::class, [], function (Smarty $smarty) { $smarty->setTemplateDir('./templates/'); $smarty->setCompileDir('./templates_c/'); $smarty->setConfigDir('./config/'); $smarty->setCacheDir('./cache/'); }); // Atribuir dados do modelo Flight::view()->assign('name', 'Bob'); // Exibir o modelo Flight::view()->display('hello.tpl');
Para completude, você também deve substituir o método de renderização padrão do Flight:
Flight::map('render', function(string $template, array $data): void { Flight::view()->assign($data); Flight::view()->display($template); });
Flight proporciona por defecto alguna funcionalidad básica de plantillas.
Si necesita necesidades de plantillas más complejas, consulte los ejemplos de Smarty y Latte en la sección de Vistas Personalizadas.
Para mostrar una plantilla de vista, llame al método render con el nombre del archivo de la plantilla y datos de plantilla opcionales:
Los datos de plantilla que pasa se inyectan automáticamente en la plantilla y se pueden hacer referencia como una variable local. Los archivos de plantilla son simplemente archivos PHP. Si el contenido del archivo de plantilla hello.php es:
¡Hola, <?= $name ?>!
La salida sería:
¡Hola, Bob!
También puede establecer manualmente las variables de vista utilizando el método set:
La variable name ahora está disponible en todas sus vistas. Entonces simplemente puede hacer:
Tenga en cuenta que al especificar el nombre de la plantilla en el método de representación, puede omitir la extensión .php.
De forma predeterminada, Flight buscará un directorio views para archivos de plantilla. Puede establecer una ruta alternativa para sus plantillas configurando lo siguiente:
Flight::set('flight.views.path', '/ruta/a/views');
Es común que los sitios web tengan un solo archivo de plantilla de diseño con contenido intercambiable. Para renderizar contenido que se utilizará en un diseño, puede pasar un parámetro opcional al método render.
Flight::render('header', ['heading' => 'Hola'], 'headerContent'); Flight::render('body', ['body' => 'Mundo'], 'bodyContent');
Entonces su vista tendrá variables guardadas llamadas headerContent y bodyContent. Luego puede renderizar su diseño haciendo:
Flight::render('layout', ['title' => 'Página de inicio']);
Si los archivos de plantilla se ven así:
<html> <head> <title><?= $title ?></title> </head> <body> <?= $heaterContent ?> <?= $bodyContent ?> </body> </html>
<html> <head> <title>Página de inicio</title> </head> <body> <h1>Hola</h1> <div>Mundo</div> </body> </html>
Flight le permite cambiar el motor de vista predeterminado simplemente registrando su propia clase de vista.
Así es como usaría el Smarty motor de plantillas para sus vistas:
// Cargar biblioteca de Smarty require './Smarty/libs/Smarty.class.php'; // Registrar Smarty como la clase de vista // También pase una función de devolución de llamada para configurar Smarty al cargar Flight::register('view', Smarty::class, [], function (Smarty $smarty) { $smarty->setTemplateDir('./templates/'); $smarty->setCompileDir('./templates_c/'); $smarty->setConfigDir('./config/'); }); // Asignar datos de plantilla Flight::view()->assign('name', 'Bob'); // Mostrar la plantilla Flight::view()->display('hello.tpl');
Para completar, también debe anular el método de representación predeterminado de Flight:
Así es como usaría el Latte motor de plantillas para sus vistas:
// Registrar Latte como la clase de vista // También pase una función de devolución de llamada para configurar Latte al cargar Flight::register('view', Latte\Engine::class, [], function (Latte\Engine $latte) { // Aquí es donde Latte almacenará en caché sus plantillas para acelerar las cosas // ¡Una característica interesante de Latte es que actualiza automáticamente su // caché cuando realiza cambios en sus plantillas! $latte->setTempDirectory(__DIR__ . '/../cache/'); // Indique a Latte dónde estará el directorio raíz de sus vistas. $latte->setLoader(new \Latte\Loaders\FileLoader(__DIR__ . '/../views/')); }); // Y envuélvalo para que pueda usar Flight::render() correctamente Flight::map('render', function(string $template, array $data): void { // Esto es como $latte_engine->render($template, $data); echo Flight::view()->render($template, $data); });
Sem Gordura (afetuosamente conhecido como SG) é um microframework PHP poderoso, mas fácil de usar, projetado para ajudá-lo a construir aplicativos web dinâmicos e robustos - rapidamente!
Voo se compara com Sem Gordura de muitas maneiras e provavelmente é o parente mais próximo em termos de recursos e simplicidade. Sem Gordura tem muitos recursos que Voo não tem, mas também tem muitos recursos que Voo tem. Sem Gordura está começando a mostrar sua idade e não é tão popular quanto já foi.
As atualizações estão se tornando menos frequentes e a comunidade não é mais tão ativa quanto já foi. O código é simples o suficiente, mas às vezes a falta de disciplina sintática pode tornar difícil de ler e entender. Ele funciona para o PHP 8.3, mas o código em si ainda parece que pertence ao PHP 5.3.
GET
DB\SQL
active-record
Cache
beforeroute
afterroute
HIVE
Flight é projetado para ser um framework extensível. O framework vem com um conjunto de métodos e componentes padrão, mas permite que você mapeie seus próprios métodos, registre suas próprias classes ou até mesmo substitua classes e métodos existentes.
Se você está procurando por um DIC (Dependency Injection Container), vá para a página Dependency Injection Container.
Para mapear seu próprio método personalizado simples, você usa a função map:
// Mapeie seu método Flight::map('hello', function (string $name) { echo "olá $name!"; }); // Chame seu método personalizado Flight::hello('Bob');
Embora seja possível criar métodos personalizados simples, é recomendado apenas criar funções padrão em PHP. Isso tem autocompletar em IDEs e é mais fácil de ler. O equivalente do código acima seria:
function hello(string $name) { echo "olá $name!"; } hello('Bob');
Isso é mais utilizado quando você precisa passar variáveis para o método para obter um valor esperado. Usando o método register() como mostrado abaixo é mais para passar configuração e então chamar sua classe pré-configurada.
register()
Para registrar sua própria classe e configurá-la, você usa a função register:
// Registre sua classe Flight::register('user', User::class); // Obtenha uma instância de sua classe $user = Flight::user();
O método de registro também permite que você passe parâmetros para o construtor de sua classe Assim, quando você carrega sua classe personalizada, ela será pré-inicializada. Você pode definir os parâmetros do construtor passando um array adicional. Aqui está um exemplo de carregar uma conexão de banco de dados:
// Registrar classe com parâmetros do construtor Flight::register('db', PDO::class, ['mysql:host=localhost;dbname=test', 'user', 'pass']); // Obtenha uma instância de sua classe // Isso criará um objeto com os parâmetros definidos // // new PDO('mysql:host=localhost;dbname=test','user','pass'); // $db = Flight::db(); // e se você precisasse mais tarde em seu código, basta chamar o mesmo método novamente class SomeController { public function __construct() { $this->db = Flight::db(); } }
Se você passar um parâmetro de retorno de chamada adicional, ele será executado imediatamente após a construção da classe. Isso permite que você execute quaisquer procedimentos de configuração para o novo objeto. A função de retorno de chamada recebe um parâmetro, uma instância do novo objeto.
// O retorno de chamada receberá o objeto que foi construído Flight::register( 'db', PDO::class, ['mysql:host=localhost;dbname=test', 'user', 'pass'], function (PDO $db) { $db->setAttribute(PDO::ATTR_ERRMODE, PDO::ERRMODE_EXCEPTION); } );
Por padrão, toda vez que você carrega sua classe, você obterá uma instância compartilhada. Para obter uma nova instância de uma classe, basta passar false como parâmetro:
// Instância compartilhada da classe $compartilhado = Flight::db(); // Nova instância da classe $nova = Flight::db(false);
Lembre-se de que os métodos mapeados têm precedência sobre as classes registradas. Se você declarar ambos com o mesmo nome, apenas o método mapeado será invocado.
Flight permite que você sobreponha sua funcionalidade padrão para atender às suas próprias necessidades, sem ter que modificar nenhum código. Você pode ver todos os métodos que você pode sobrepor aqui.
Por exemplo, quando o Flight não consegue corresponder uma URL a uma rota, ele invoca o método notFound que envia uma resposta genérica de HTTP 404. Você pode substituir esse comportamento usando o método map:
Flight::map('notFound', function() { // Mostrar página de erro personalizada 404 include 'errors/404.html'; });
Flight também permite que você substitua componentes centrais do framework. Por exemplo, você pode substituir a classe de Router padrão por sua própria classe personalizada:
// Registre sua classe personalizada Flight::register('router', MyRouter::class); // Quando o Flight carrega a instância do Router, ele carregará sua classe $myrouter = Flight::router();
Métodos do Framework como map e register não podem ser sobrepostos. Você irá receber um erro se tentar fazer isso.
# JSON Flight fornece suporte para o envio de respostas JSON e JSONP. Para enviar uma resposta JSON, você passa alguns dados a serem codificados em JSON: ```php Flight::json(['id' => 123]);
Para solicitações JSONP, você pode passar opcionalmente o nome do parâmetro de consulta que está usando para definir sua função de retorno de chamada:
Portanto, ao fazer uma solicitação GET usando ?q=my_func, você deve receber a saída:
Se você não passar um nome de parâmetro de consulta, ele será padrão para jsonp.
Slim é um microframework PHP que ajuda você a escrever rapidamente aplicações web e APIs simples, porém poderosas.
Muita da inspiração para algumas das funcionalidades da versão 3 do Flight na verdade veio do Slim. Agrupar rotas e executar middleware em uma ordem específica são duas funcionalidades que foram inspiradas pelo Slim. O Slim v3 foi lançado voltado para a simplicidade, mas houve críticas mistas em relação ao v4.
O carregamento automático é um conceito em PHP onde você especifica um diretório ou diretórios para carregar classes. Isso é muito mais benéfico do que usar require ou include para carregar classes. Também é um requisito para usar pacotes do Composer.
require
include
Por padrão, qualquer classe Flight é carregada automaticamente graças ao Composer. No entanto, se você deseja carregar suas próprias classes, pode usar o método Flight::path() para especificar um diretório para carregar classes.
Flight::path()
Vamos assumir que temos uma estrutura de diretórios como a seguinte:
# Caminho de Exemplo /home/user/project/my-flight-project/ ├── app │ ├── cache │ ├── config │ ├── controllers - contém os controladores para este projeto │ ├── translations │ ├── UTILS - contém classes apenas para esta aplicação (tudo em maiúsculas de propósito para um exemplo posterior) │ └── views └── public └── css └── js └── index.php
Você pode especificar cada diretório a ser carregado da seguinte maneira:
/** * public/index.php */ // Adicionar um caminho ao carregador automático Flight::path(__DIR__.'/../app/controllers/'); Flight::path(__DIR__.'/../app/utils/'); /** * app/controllers/MyController.php */ // sem necessidade de namespace // Todas as classes carregadas automaticamente são recomendadas a serem em Pascal Case (cada palavra capitalizada, sem espaços) // A partir da versão 3.7.2, você pode usar Pascal_Snake_Case para os nomes de suas classes executando Loader::setV2ClassLoading(false); class MyController { public function index() { // fazer algo } }
Se você tiver namespaces, na verdade se torna muito fácil implementar isso. Você deve usar o método Flight::path() para especificar o diretório raiz (não o diretório do documento ou pasta public/) de sua aplicação.
public/
/** * public/index.php */ // Adicionar um caminho ao carregador automático Flight::path(__DIR__.'/../');
Agora, veja como seu controlador poderia ser. Observe o exemplo abaixo, mas preste atenção aos comentários para informações importantes.
/** * app/controllers/MyController.php */ // namespaces são necessários // os namespaces são iguais à estrutura de diretórios // os namespaces devem seguir o mesmo padrão de caso que a estrutura de diretórios // os namespaces e diretórios não podem ter nenhum sublinhado (a menos que Loader::setV2ClassLoading(false) seja definido) namespace app\controllers; // Todas as classes carregadas automaticamente são recomendadas a serem em Pascal Case (cada palavra capitalizada, sem espaços) // A partir da versão 3.7.2, você pode usar Pascal_Snake_Case para os nomes de suas classes executando Loader::setV2ClassLoading(false); class MyController { public function index() { // fazer algo } }
E se você quiser carregar automaticamente uma classe em seu diretório de utils, você faria basicamente a mesma coisa:
/** * app/UTILS/ArrayHelperUtil.php */ // o namespace deve corresponder à estrutura de diretórios e caso (observe que o diretório UTILS está todo em maiúsculas // como na árvore de arquivos acima) namespace app\UTILS; class ArrayHelperUtil { public function changeArrayCase(array $array) { // fazer algo } }
A partir da versão 3.7.2, você pode usar Pascal_Snake_Case para os nomes de suas classes executando Loader::setV2ClassLoading(false);. Isso permitirá que você use sublinhados em seus nomes de classe. Isso não é recomendado, mas está disponível para aqueles que precisam.
Loader::setV2ClassLoading(false);
/** * public/index.php */ // Adicionar um caminho ao carregador automático Flight::path(__DIR__.'/../app/controllers/'); Flight::path(__DIR__.'/../app/utils/'); Loader::setV2ClassLoading(false); /** * app/controllers/My_Controller.php */ // sem necessidade de namespace class My_Controller { public function index() { // fazer algo } }
# Solução de problemas Esta página irá ajudá-lo a resolver problemas comuns que você pode encontrar ao usar o Flight. ## Problemas Comuns ### 404 Não Encontrado ou Comportamento de Rota Inesperado Se você estiver vendo um erro 404 Não Encontrado (mas jura pela sua vida que está realmente lá e não é um erro de digitação) isso poderia realmente ser um problema com você retornando um valor no ponto final da sua rota em vez de apenas ecoá-lo. A razão para isso é intencional, mas pode pegar alguns desenvolvedores de surpresa. ```php Flight::route('/hello', function(){ // Isso pode causar um erro 404 Não Encontrado return 'Olá Mundo'; }); // O que você provavelmente quer Flight::route('/hello', function(){ echo 'Olá Mundo'; });
A razão para isso é por causa de um mecanismo especial incorporado no roteador que trata a saída de retorno como um sinal para "ir para a próxima rota". Você pode ver o comportamento documentado na seção de Roteamento.
Podem haver algumas razões para isso não estar funcionando. Abaixo estão alguns exemplos, mas certifique-se também de verificar a seção de autoload.
O mais comum é que o nome da classe não corresponda ao nome do arquivo.
Se você tem uma classe chamada MyClass, então o arquivo deve ser chamado MyClass.php. Se você tem uma classe chamada MyClass e o arquivo é chamado myclass.php então o autoload não será capaz de encontrá-lo.
MyClass
MyClass.php
myclass.php
Se estiver usando namespaces, então o namespace deve corresponder à estrutura de diretórios.
// código // se o seu MyController estiver no diretório app/controllers e estiver em um namespace // isso não funcionará Flight::route('/hello', 'MyController->hello'); // você precisará escolher uma dessas opções Flight::route('/hello', 'app\controllers\MyController->hello'); // ou se você tiver um comando use no topo use app\controllers\MyController; Flight::route('/hello', [ MyController::class, 'hello' ]); // também pode ser escrito Flight::route('/hello', MyController::class.'->hello'); // também... Flight::route('/hello', [ 'app\controllers\MyController', 'hello' ]);
path()
No aplicativo skeleton, isso é definido dentro do arquivo config.php, mas para que suas classes sejam encontradas, você precisa garantir que o método path() esteja definido (provavelmente na raiz do seu diretório) antes de tentar usá-lo.
config.php
// Adicione um caminho ao autoload Flight::path(__DIR__.'/../');
Se estiver a usar Composer, pode executar o seguinte comando:
composer require flightphp/core
OU então pode baixar os arquivos diretamente e extrair para o seu diretório web.
Para o Apache, edite o seu ficheiro .htaccess com o seguinte:
.htaccess
RewriteEngine On RewriteCond %{REQUEST_FILENAME} !-f RewriteCond %{REQUEST_FILENAME} !-d RewriteRule ^(.*)$ index.php [QSA,L]
Nota: Se necessitar de utilizar o Flight numa subpasta, adicione a linha RewriteBase /subdir/ logo após RewriteEngine On. Nota: Se quiser proteger todos os ficheiros do servidor, como um ficheiro de bd ou env. Coloque isto no seu ficheiro .htaccess:
Nota: Se necessitar de utilizar o Flight numa subpasta, adicione a linha RewriteBase /subdir/ logo após RewriteEngine On.
RewriteBase /subdir/
RewriteEngine On
Nota: Se quiser proteger todos os ficheiros do servidor, como um ficheiro de bd ou env. Coloque isto no seu ficheiro .htaccess:
RewriteEngine On RewriteRule ^(.*)$ index.php
Para o Nginx, adicione o seguinte à declaração do seu servidor:
server { location / { try_files $uri $uri/ /index.php; } }
<?php // Se estiver a usar o Composer, requer o autoloader. require 'vendor/autoload.php'; // se não estiver a usar o Composer, carregue o framework diretamente // require 'flight/Flight.php'; // Depois defina uma rota e atribua uma função para lidar com o pedido. Flight::route('/', function () { echo 'hello world!'; }); // Por fim, inicie o framework. Flight::start();
Direitos de autor © 2024 @mikecao, @n0nag0n
2024
@mikecao, @n0nag0n
É concedida permissão, gratuitamente, a qualquer pessoa que obtenha uma cópia deste software e documentação associada (arquivo PDF), para lidar com o software sem restrições, incluindo, sem limitação, os direitos de usar, copiar, modificar, mesclar, publicar, distribuir, sublicenciar e/ou vender cópias do software, e permitir que as pessoas a quem o software é fornecido o façam, sujeito às seguintes condições:
O aviso de direitos de autor acima e este aviso de permissão devem ser incluídos em todas as cópias ou partes substanciais do software.
O SOFTWARE É FORNECIDO "COMO ESTÁ", SEM GARANTIA DE QUALQUER TIPO, EXPRESSA OU IMPLÍCITA, INCLUINDO, MAS NÃO SE LIMITANDO ÀS GARANTIAS DE COMERCIALIZAÇÃO, ADEQUAÇÃO A UM FIM ESPECÍFICO E NÃO VIOLAÇÃO. EM NENHUM CASO OS AUTORES OU DETENTORES DE DIREITOS AUTORAIS SERÃO RESPONSÁVEIS POR QUALQUER REIVINDICAÇÃO, DANOS OU OUTRA RESPONSABILIDADE, SEJA EM UMA AÇÃO DE CONTRATO, DELITO OU DE OUTRA FORMA, DECORRENTE DE, FORA DE OU EM CONEXÃO COM O SOFTWARE OU O USO OU OUTROS ACORDOS NO SOFTWARE.
Flight é um framework rápido, simples e extensível para PHP. É bastante versátil e pode ser usado para construir qualquer tipo de aplicação web. É construído com simplicidade em mente e é escrito de uma forma que é fácil de entender e utilizar.
Flight é um ótimo framework para iniciantes que são novos no PHP e desejam aprender como construir aplicações web. Também é um ótimo framework para desenvolvedores experientes que desejam ter mais controle sobre suas aplicações web. É projetado para construir facilmente uma API RESTful, uma aplicação web simples ou uma aplicação web complexa.
<?php // se instalado com composer require 'vendor/autoload.php'; // ou se instalado manualmente por arquivo zip // require 'flight/Flight.php'; Flight::route('/', function() { echo 'olá mundo!'; }); Flight::route('/json', function() { Flight::json(['hello' => 'world']); }); Flight::start();
Simples o suficiente, certo? Saiba mais sobre o Flight na documentação!
Há um app de exemplo que pode ajudá-lo a começar com o Framework Flight. Acesse flightphp/skeleton para instruções sobre como começar! Você também pode visitar a página exemplos para se inspirar em algumas das coisas que você pode fazer com o Flight.
Estamos no Chat do Matrix, converse conosco em #flight-php-framework:matrix.org.
Existem duas maneiras pelas quais você pode contribuir com o Flight:
Flight requer PHP 7.4 ou superior.
Nota: PHP 7.4 é suportado porque no momento atual da escrita (2024), o PHP 7.4 é a versão padrão para algumas distribuições LTS do Linux. Forçar a migração para o PHP >8 causaria muitos problemas para esses usuários. O framework também suporta PHP >8.
O Flight é lançado sob a licença MIT.
overclokk/cookie é uma biblioteca simples para gerenciar cookies em seu aplicativo.
A instalação é simples com o composer.
composer require overclokk/cookie
O uso é tão simples quanto registrar um novo método na classe Flight.
use Overclokk\Cookie\Cookie; /* * Defina em seu arquivo de inicialização ou public/index.php */ Flight::register('cookie', Cookie::class); /** * ExampleController.php */ class ExampleController { public function login() { // Defina um cookie // você vai querer que isso seja falso para obter uma nova instância // use o comentário abaixo se quiser autocompletar /** @var \Overclokk\Cookie\Cookie $cookie */ $cookie = Flight::cookie(false); $cookie->set( 'stay_logged_in', // nome do cookie '1', // o valor que você deseja definir 86400, // número de segundos que o cookie deve durar '/', // caminho em que o cookie estará disponível 'example.com', // domínio em que o cookie estará disponível true, // o cookie só será transmitido por uma conexão HTTPS segura true // o cookie só estará disponível por meio do protocolo HTTP ); // opcionalmente, se você quiser manter os valores padrão // e ter uma maneira rápida de definir um cookie por um longo tempo $cookie->forever('stay_logged_in', '1'); } public function home() { // Verifique se você tem o cookie if (Flight::cookie()->has('stay_logged_in')) { // colocá-los na área do painel, por exemplo. Flight::redirect('/dashboard'); } } }
defuse/php-encryption é uma biblioteca que pode ser usada para criptografar e descriptografar dados. Começar a usar é bastante simples para começar a criptografar e descriptografar dados. Eles têm um ótimo tutorial que ajuda a explicar o básico de como usar a biblioteca, bem como importantes implicações de segurança relacionadas à criptografia.
composer require defuse/php-encryption
Em seguida, você precisará gerar uma chave de criptografia.
vendor/bin/generate-defuse-key
Isso vai gerar uma chave que você precisará manter em segurança. Você poderia guardar a chave em seu arquivo app/config/config.php no array no final do arquivo. Embora não seja o local perfeito, é pelo menos algo.
app/config/config.php
Agora que você tem a biblioteca e uma chave de criptografia, você pode começar a criptografar e descriptografar dados.
use Defuse\Crypto\Crypto; use Defuse\Crypto\Key; /* * Defina em seu arquivo de inicialização ou public/index.php */ // Método de criptografia Flight::map('encrypt', function($dados_brutos) { $chave_criptografia = /* $config['encryption_key'] ou um file_get_contents de onde você colocou a chave */; return Crypto::encrypt($dados_brutos, Key::loadFromAsciiSafeString($chave_criptografia)); }); // Método de descriptografia Flight::map('decrypt', function($dados_criptografados) { $chave_criptografia = /* $config['encryption_key'] ou um file_get_contents de onde você colocou a chave */; try { $dados_brutos = Crypto::decrypt($dados_criptografados, Key::loadFromAsciiSafeString($chave_criptografia)); } catch (Defuse\Crypto\Exception\WrongKeyOrModifiedCiphertextException $ex) { // Um ataque! Ou a chave errada foi carregada, ou o texto cifrado foi // alterado desde que foi criado - corrompido no banco de dados ou // intencionalmente modificado por Eve tentando realizar um ataque. // ... trate este caso de uma maneira adequada à sua aplicação ... } return $dados_brutos; }); Flight::route('/encrypt', function() { $dados_criptografados = Flight::encrypt('Isto é um segredo'); echo $dados_criptografados; }); Flight::route('/decrypt', function() { $dados_criptografados = '...'; // Obtenha os dados criptografados de algum lugar $dados_descriptografados = Flight::decrypt($dados_criptografados); echo $dados_descriptografados; });
Classe standalone de cache de arquivo PHP leve e simples
Vantagens
Clique aqui para visualizar o código.
Instale via composer:
composer require wruczek/php-file-cache
O uso é bastante direto.
use Wruczek\PhpFileCache\PhpFileCache; $app = Flight::app(); // Você passa o diretório no qual o cache será armazenado para o construtor $app->register('cache', PhpFileCache::class, [ __DIR__ . '/../cache/' ], function(PhpFileCache $cache) { // Isso garante que o cache seja usado apenas no modo de produção // AMBIENTE é uma constante definida em seu arquivo de inicialização ou em outro lugar de seu aplicativo $cache->setDevMode(ENVIRONMENT === 'development'); });
Então você pode usá-lo em seu código assim:
// Obter instância de cache $cache = Flight::cache(); $data = $cache->refreshIfExpired('simple-cache-test', function () { return date("H:i:s"); // retornar dados a serem armazenados em cache }, 10); // 10 segundos // ou $data = $cache->retrieve('simple-cache-test'); if(empty($data)) { $data = date("H:i:s"); $cache->store('simple-cache-test', $data, 10); // 10 segundos }
Visite https://github.com/Wruczek/PHP-File-Cache para ver a documentação completa e certifique-se de ver a pasta de exemplos.
Este é um módulo de permissões que pode ser usado em seus projetos se você tiver vários papéis em seu aplicativo e cada papel tiver funcionalidades um pouco diferentes. Este módulo permite que você defina permissões para cada papel e depois verifique se o usuário atual tem permissão para acessar uma determinada página ou realizar uma determinada ação.
Clique aqui para acessar o repositório no GitHub.
Execute composer require flightphp/permissions e pronto!
composer require flightphp/permissions
Primeiro, você precisa configurar suas permissões e, em seguida, informar ao seu aplicativo o que as permissões significam. Por fim, você verificará suas permissões com $Permissions->has(), ->can() ou is(). has() e can() têm a mesma funcionalidade, mas têm nomes diferentes para tornar seu código mais legível.
$Permissions->has()
->can()
is()
has()
can()
Vamos supor que você tenha um recurso em seu aplicativo que verifica se um usuário está conectado. Você pode criar um objeto de permissões assim:
// index.php require 'vendor/autoload.php'; // algum código // então você provavelmente tem algo que diz qual é o papel atual da pessoa // provavelmente você tem algo que puxa o papel atual // de uma variável de sessão que define isso // depois que alguém faz o login, caso contrário eles terão um papel 'convidado' ou 'público'. $current_role = 'admin'; // configurar permissões $permission = new \flight\Permission($current_role); $permission->defineRule('conectado', function($current_role) { return $current_role !== 'convidado'; }); // Você provavelmente vai querer persistir este objeto em algum lugar do Flight Flight::set('permissão', $permissão);
Então em um controlador em algum lugar, você pode ter algo assim.
<?php // algum controlador class AlgunsController { public function algumaAção() { $permissão = Flight::get('permissão'); if ($permissão->has('conectado')) { // faça algo } else { // faça algo diferente } } }
Você também pode usar isso para rastrear se têm permissão para fazer algo em seu aplicativo. Por exemplo, se você tiver uma forma dos usuários interagirem com postagens em seu software, você pode verificar se eles têm permissão para realizar certas ações.
$current_role = 'admin'; // configurar permissões $permission = new \flight\Permission($current_role); $permission->defineRule('postagem', function($current_role) { if($current_role === 'admin') { $permissões = ['criar', 'ler', 'atualizar', 'apagar']; } else if($current_role === 'editor') { $permissões = ['criar', 'ler', 'atualizar']; } else if($current_role === 'autor') { $permissões = ['criar', 'ler']; } else if($current_role === 'contribuidor') { $permissões = ['criar']; } else { $permissões = []; } return $permissões; }); Flight::set('permissão', $permissão);
Então em um controlador em algum lugar...
class ControladorDePostagem { public function criar() { $permissão = Flight::get('permissão'); if ($permissão->can('postagem.criar')) { // faça algo } else { // faça algo diferente } } }
Você pode injetar dependências no fechamento que define as permissões. Isso é útil se você tiver algum tipo de alternância, id ou qualquer outro ponto de dados que deseja verificar. O mesmo funciona para chamadas de Tipo Classe->Método, exceto que você define os argumentos no método.
$Permission->defineRule('pedido', function(string $current_role, MyDependency $MyDependency = null) { // ... código }); // em seu arquivo de controlador public function criarPedido() { $MyDependency = Flight::myDependency(); $permissão = Flight::get('permissão'); if ($permissão->can('pedido.criar', $MyDependency)) { // faça algo } else { // faça algo diferente } }
namespace MyApp; class Permissões { public function pedido(string $current_role, MyDependency $MyDependency = null) { // ... código } }
Você também pode usar classes para definir suas permissões. Isso é útil se você tiver muitas permissões e quiser manter seu código limpo. Você pode fazer algo assim:
<?php // código de inicialização $Permissões = new \flight\Permission($current_role); $Permissões->defineRule('pedido', 'MyApp\Permissões->pedido'); // myapp/Permissões.php namespace MyApp; class Permissões { public function pedido(string $current_role, int $id_usuario) { // Pressupondo que você configurou isso antecipadamente /** @var \flight\database\PdoWrapper $db */ $db = Flight::db(); $permissões_permitidas = [ 'ler' ]; // todos podem visualizar um pedido if($current_role === 'gerente') { $permissões_permitidas[] = 'criar'; // gerentes podem criar pedidos } $alguma_alternancia_especial_do_db = $db->fetchField('SELECT alguma_alternancia_especial FROM ajustes WHERE id = ?', [ $id_usuario ]); if($alguma_alternancia_especial_do_db) { $permissões_permitidas[] = 'atualizar'; // se o usuário tiver uma alternância especial, ele pode atualizar pedidos } if($current_role === 'admin') { $permissões_permitidas[] = 'apagar'; // administradores podem excluir pedidos } return $permissões_permitidas; } }
A parte legal é que também há um atalho que você pode usar (que também pode ser cacheado!!!) onde você apenas diz à classe de permissões para mapear todos os métodos de uma classe em permissões. Portanto, se você tiver um método chamado pedido() e um método chamado empresa(), esses serão mapeados automaticamente para que você possa simplesmente executar $Permissões->has('pedido.ler') ou `$Permissões->has('empresa.ler') e isso funcionará. Definir isso é muito difícil, então fique comigo aqui. Você só precisa fazer o seguinte:
pedido()
empresa()
$Permissões->has('pedido.ler')
Crie a classe de permissões que deseja agrupar.
class MinhasPermissões { public function pedido(string $current_role, int $id_pedido = 0): array { // código para determinar permissões return $array_de_permissoes; } public function empresa(string $current_role, int $id_empresa): array { // código para determinar permissões return $array_de_permissoes; } }
Em seguida, torne as permissões descobríveis usando esta biblioteca.
$Permissões = new \flight\Permission($current_role); $Permissões->defineRulesFromClassMethods(MyApp\Permissões::class); Flight::set('permissões', $Permissões);
Finalmente, chame a permissão em sua base de código para verificar se o usuário tem permissão para realizar uma determinada permissão.
class AlgunsControlador { public function criarPedido() { if(Flight::get('permissões')->can('pedido.criar') === false) { die('Você não pode criar um pedido. Desculpe!'); } } }
Para habilitar o cache, consulte a simples biblioteca wruczak/phpfilecache. Um exemplo de habilitação está abaixo.
// este $app pode fazer parte do seu código, ou // você pode simplesmente passar null e ele irá // puxar de Flight::app() no construtor $app = Flight::app(); // Por enquanto, aceita isso como um cache de arquivo. Outros podem ser facilmente // adicionados no futuro. $Cache = new Wruczek\PhpFileCache\PhpFileCache; $Permissões = new \flight\Permission($current_role, $app, $Cache); $Permissões->defineRulesFromClassMethods(MyApp\Permissões::class, 3600); // 3600 é quantos segundos para armazenar em cache. Deixe isso de fora para não usar o cache
O Flight é incrivelmente extensível. Existem vários plugins que podem ser usados para adicionar funcionalidades à sua aplicação Flight. Alguns são oficialmente suportados pela Equipe do Flight e outros são bibliotecas micro/lite para ajudá-lo a começar.
O armazenamento em cache é uma ótima maneira de acelerar a sua aplicação. Existem diversas bibliotecas de cache que podem ser usadas com o Flight.
Depurar é crucial quando você está desenvolvendo no seu ambiente local. Existem alguns plugins que podem aprimorar a sua experiência de depuração.
Os bancos de dados são a base da maioria das aplicações. É assim que você armazena e recupera dados. Algumas bibliotecas de banco de dados são simplesmente wrappers para escrever consultas e outras são ORMs completos.
As sessões não são realmente úteis para APIs, mas para desenvolver uma aplicação web, as sessões podem ser cruciais para manter o estado e as informações de login.
A criação de modelos é essencial para qualquer aplicação web com uma interface de usuário. Existem várias engines de templates que podem ser usadas com o Flight.
Tem um plugin que gostaria de compartilhar? Envie uma solicitação pull para adicioná-lo à lista!
Gerenciador de Sessão PHP (não bloqueante, flash, segmento, criptografia de sessão). Usa PHP open_ssl para criptografia/descriptografia opcional de dados de sessão. Suporta Arquivo, MySQL, Redis e Memcached.
Instale com o compositor.
composer require ghostff/session
Não é necessário passar nada para usar as configurações padrão com sua sessão. Você pode ler sobre mais configurações no [README do Github] (https://github.com/Ghostff/Session).
use Ghostff\Session\Session; require 'vendor/autoload.php'; $app = Flight::app(); $app->register('session', Session::class); // uma coisa a lembrar é que você deve confirmar sua sessão em cada carregamento de página // ou você precisará executar auto_commit em sua configuração.
Aqui está um exemplo simples de como você pode usar isso.
Flight::route('POST /login', function() { $session = Flight::session(); // faça sua lógica de login aqui // validar senha, etc. // se o login for bem-sucedido $session->set('is_logged_in', true); $session->set('user', $user); // toda vez que você escreve na sessão, deve confirmá-la deliberadamente. $session->commit(); }); // Esta verificação pode estar na lógica da página restrita ou envolvida com middleware. Flight::route('/alguma-pagina-restrita', function() { $session = Flight::session(); if(!$session->get('is_logged_in')) { Flight::redirect('/login'); } // faça sua lógica de página restrita aqui }); // a versão do middleware Flight::route('/alguma-pagina-restrita', function() { // lógica regular da página })->addMiddleware(function() { $session = Flight::session(); if(!$session->get('is_logged_in')) { Flight::redirect('/login'); } });
Aqui está um exemplo mais complexo de como você pode usar isso.
use Ghostff\Session\Session; require 'vendor/autoload.php'; $app = Flight::app(); // defina um caminho personalizado para o arquivo de configuração da sessão e forneça uma string aleatória para o id da sessão $app->register('session', Session::class, [ 'caminho/para/session_config.php', bin2hex(random_bytes(32)) ], function(Session $session) { // ou você pode substituir manualmente as opções de configuração $session->updateConfiguration([ // se deseja armazenar seus dados de sessão em um banco de dados (bom se deseja algo como, "sair de todos os dispositivos" funcionalidade) Session::CONFIG_DRIVER => Ghostff\Session\Drivers\MySql::class, Session::CONFIG_ENCRYPT_DATA => true, Session::CONFIG_SALT_KEY => hash('sha256', 'minha-super-senha-S3CR3TA'), // por favor, mude isso para ser algo diferente Session::CONFIG_AUTO_COMMIT => true, // faça isso apenas se for necessário e/ou for difícil confirmar() sua sessão. // adicionalmente você poderia fazer Flight::after('start', function() { Flight::session()->commit(); }); Session::CONFIG_MYSQL_DS => [ 'driver' => 'mysql', # Driver de banco de dados para o dns do PDO, por exemplo (mysql:host=...;dbname=...) 'host' => '127.0.0.1', # Host do banco de dados 'db_name' => 'meu_banco_de_dados_do_aplicativo', # Nome do banco de dados 'db_table' => 'sessoes', # Tabela do banco de dados 'db_user' => 'root', # Nome de usuário do banco de dados 'db_pass' => '', # Senha do banco de dados 'persistent_conn'=> false, # Evite o overhead de estabelecer uma nova conexão toda vez que um script precisa se comunicar com um banco de dados, resultando em uma aplicação web mais rápida. ENCONTRE O LADO NEGATIVO VOCÊ MESMO ] ]); } );
Você está definindo seus dados de sessão e eles não estão persistindo entre as solicitações? Você pode ter esquecido de confirmar seus dados de sessão. Você pode fazer isso chamando $session->commit() depois de definir seus dados de sessão.
$session->commit()
Flight::route('POST /login', function() { $session = Flight::session(); // faça sua lógica de login aqui // validar senha, etc. // se o login for bem-sucedido $session->set('is_logged_in', true); $session->set('user', $user); // toda vez que você escreve na sessão, deve confirmá-la deliberadamente. $session->commit(); });
A outra maneira de contornar isso é ao configurar seu serviço de sessão, você tem que definir auto_commit como true em sua configuração. Isso irá confirmar automaticamente seus dados de sessão após cada solicitação.
auto_commit
$app->register('session', Session::class, [ 'caminho/para/session_config.php', bin2hex(random_bytes(32)) ], function(Session $session) { $session->updateConfiguration([ Session::CONFIG_AUTO_COMMIT => true, ]); } );
Além disso, você poderia fazer Flight::after('start', function() { Flight::session()->commit(); }); para confirmar seus dados de sessão após cada solicitação.
Flight::after('start', function() { Flight::session()->commit(); });
Visite o README do Github para documentação completa. As opções de configuração são bem documentadas no arquivo default_config.php em si. O código é simples de entender se você quiser examinar este pacote por conta própria.
A Pista é uma aplicação CLI que ajuda a gerenciar suas aplicações Flight. Ela pode gerar controladores, exibir todas as rotas e mais. É baseada na excelente biblioteca adhocore/php-cli.
Instale com o composer.
composer require flightphp/runway
Na primeira execução da Pista, ela guiará você por um processo de configuração e criará um arquivo de configuração .runway.json na raiz do seu projeto. Este arquivo conterá algumas configurações necessárias para que a Pista funcione corretamente.
.runway.json
A Pista possui vários comandos que você pode usar para gerenciar sua aplicação Flight. Existem duas maneiras fáceis de usar a Pista.
php runway [comando]
vendor/bin/runway [comando]
Para qualquer comando, você pode inserir a flag --help para obter mais informações sobre como utilizar o comando.
--help
php runway routes --help
Aqui estão alguns exemplos:
Com base na configuração em seu arquivo .runway.json, a localização padrão gerará um controlador para você no diretório app/controllers/.
app/controllers/
php runway make:controller MeuControlador
Com base na configuração em seu arquivo .runway.json, a localização padrão gerará um controlador para você no diretório app/records/.
app/records/
php runway make:record usuários
Se por acaso você tiver a tabela usuários com o seguinte esquema: id, nome, email, criado_em, atualizado_em, um arquivo semelhante ao seguinte será criado no arquivo app/records/RegistroUsuario.php:
usuários
nome
email
criado_em
atualizado_em
app/records/RegistroUsuario.php
<?php declare(strict_types=1); namespace app\records; /** * Classe Active Record para a tabela de usuários. * @link https://docs.flightphp.com/awesome-plugins/active-record * * @property int $id * @property string $nome * @property string $email * @property string $criado_em * @property string $atualizado_em * // você também pode adicionar relacionamentos aqui uma vez que os definir no array $relações * @property RegistroEmpresa $empresa Exemplo de um relacionamento */ class RegistroUsuario extends \flight\ActiveRecord { /** * @var array $relações Define os relacionamentos para o modelo * https://docs.flightphp.com/awesome-plugins/active-record#relationships */ protected array $relações = []; /** * Construtor * @param mixed $conexãoBancoDados A conexão com o banco de dados */ public function __construct($conexãoBancoDados) { parent::__construct($conexãoBancoDados, 'usuários'); } }
Isso exibirá todas as rotas atualmente registradas com o Flight.
php runway routes
Se desejar visualizar apenas rotas específicas, você pode inserir uma flag para filtrar as rotas.
# Exibir apenas rotas GET php runway routes --get # Exibir apenas rotas POST php runway routes --post # etc.
Se você está criando um pacote para o Flight ou deseja adicionar seus próprios comandos personalizados ao seu projeto, pode fazer isso criando um diretório src/commands/, flight/commands/, app/commands/ ou commands/ para o seu projeto/pacote.
src/commands/
flight/commands/
app/commands/
commands/
Para criar um comando, você simplesmente estende a classe AbstractBaseCommand e implementa, no mínimo, um método __construct e um método execute.
AbstractBaseCommand
__construct
execute
<?php declare(strict_types=1); namespace flight\commands; class ComandoExemplo extends AbstractBaseCommand { /** * Construtor * * @param array<string,mixed> $config Configuração JSON de .runway-config.json */ public function __construct(array $config) { parent::__construct('make:example', 'Criar um exemplo para a documentação', $config); $this->argument('<gif-engracado>', 'O nome do gif engraçado'); } /** * Executa a função * * @return void */ public function execute(string $controlador) { $io = $this->app()->io(); $io->info('Criando exemplo...'); // Faça algo aqui $io->ok('Exemplo criado!'); } }
Consulte a Documentação do adhocore/php-cli para mais informações sobre como criar seus próprios comandos personalizados em sua aplicação Flight!
Este é um conjunto de extensões para tornar o trabalho com o Flight um pouco mais rico.
$_SESSION
Este é o Painel
E cada painel exibe informações muito úteis sobre sua aplicação!
Execute composer require flightphp/tracy-extensions --dev e está tudo pronto!
composer require flightphp/tracy-extensions --dev
Há muito pouca configuração que você precisa fazer para começar. Você precisará iniciar o depurador Tracy antes de usar isso https://tracy.nette.org/en/guide:
<?php use Tracy\Debugger; use flight\debug\tracy\TracyExtensionLoader; // código de inicialização require __DIR__ . '/vendor/autoload.php'; Debugger::enable(); // Talvez você precise especificar seu ambiente com Debugger::enable(Debugger::DEVELOPMENT) // se você usa conexões de banco de dados em seu aplicativo, há // um wrapper PDO obrigatório para usar APENAS EM DESENVOLVIMENTO (não em produção por favor!) // Tem os mesmos parâmetros que uma conexão PDO regular $pdo = new PdoQueryCapture('sqlite:test.db', 'user', 'pass'); // ou se você anexar isso ao framework Flight Flight::register('db', PdoQueryCapture::class, ['sqlite:test.db', 'user', 'pass']); // agora, sempre que você fizer uma consulta, ela capturará o tempo, a consulta e os parâmetros // Isso conecta os pontos if(Debugger::$showBar === true) { // Isto precisa ser falso ou Tracy não pode renderizar de fato :( Flight::set('flight.content_length', false); new TracyExtensionLoader(Flight::app()); } // mais código Flight::start();
Se você tiver um manipulador de sessão personalizado (como ghostff/session), você pode passar qualquer array de dados de sessão para Tracy e ele os exibirá automaticamente para você. Você passa com a chave session_data no segundo parâmetro do construtor TracyExtensionLoader.
session_data
TracyExtensionLoader
use Ghostff\Session\Session; require 'vendor/autoload.php'; $app = Flight::app(); $app->register('session', Session::class); if(Debugger::$showBar === true) { // Isto precisa ser falso ou Tracy não pode renderizar de fato :( Flight::set('flight.content_length', false); new TracyExtensionLoader(Flight::app(), [ 'session_data' => Flight::session()->getAll() ]); } // rotas e outras coisas... Flight::start();
Se você tiver o Latte instalado em seu projeto, você pode usar o painel do Latte para analisar seus modelos. Você pode passar a instância do Latte para o construtor TracyExtensionLoader com a chave latte no segundo parâmetro.
latte
use Latte\Engine; require 'vendor/autoload.php'; $app = Flight::app(); $app->register('latte', Engine::class, [], function($latte) { $latte->setTempDirectory(__DIR__ . '/temp'); // aqui é onde você adiciona o Painel do Latte ao Tracy $latte->addExtension(new Latte\Bridges\Tracy\TracyExtension); }); if(Debugger::$showBar === true) { // Isto precisa ser falso ou Tracy não pode renderizar de fato :( Flight::set('flight.content_length', false); new TracyExtensionLoader(Flight::app()); }
Tracy é um incrível manipulador de erros que pode ser usado com Flight. Possui vários painéis que podem ajudá-lo a depurar sua aplicação. É também muito fácil de estender e adicionar seus próprios painéis. A equipe do Flight criou alguns painéis especificamente para projetos do Flight com o plugin flightphp/tracy-extensions.
Instale com o compositor. E na verdade, você vai querer instalar isso sem a versão de desenvolvimento, já que o Tracy vem com um componente de tratamento de erros de produção.
composer require tracy/tracy
Existem algumas opções de configuração básicas para começar. Você pode ler mais sobre elas na Documentação do Tracy.
require 'vendor/autoload.php'; use Tracy\Debugger; // Habilitar Tracy Debugger::enable(); // Debugger::enable(Debugger::DEVELOPMENT) // às vezes você precisa ser explícito (também Debugger::PRODUCTION) // Debugger::enable('23.75.345.200'); // você também pode fornecer um array de endereços IP // Aqui é onde os erros e exceções serão registrados. Certifique-se de que este diretório exista e seja gravável. Debugger::$logDirectory = __DIR__ . '/../log/'; Debugger::$strictMode = true; // exibir todos os erros // Debugger::$strictMode = E_ALL & ~E_DEPRECATED & ~E_USER_DEPRECATED; // todos os erros exceto avisos obsoletos if (Debugger::$showBar) { $app->set('flight.content_length', false); // se a barra do Debugger estiver visível, então o comprimento do conteúdo não pode ser definido pelo Flight // Isso é específico para a Extensão do Tracy para o Flight se você incluiu isso // caso contrário, comente isso. new TracyExtensionLoader($app); }
Ao depurar seu código, existem algumas funções muito úteis para exibir dados para você.
bdump($var)
dumpe($var)
Um registro ativo é mapear uma entidade de banco de dados para um objeto PHP. Falando claramente, se você tem uma tabela de usuários no seu banco de dados, você pode "traduzir" uma linha nessa tabela para uma classe User e um objeto $user em sua base de código. Veja exemplo básico.
User
$user
Clique aqui para o repositório no GitHub.
Vamos supor que você tenha a seguinte tabela:
CREATE TABLE users ( id INTEGER PRIMARY KEY, name TEXT, password TEXT );
Agora você pode configurar uma nova classe para representar essa tabela:
/** * Uma classe ActiveRecord é geralmente singular * * É altamente recomendável adicionar as propriedades da tabela como comentários aqui * * @property int $id * @property string $name * @property string $password */ class User extends flight\ActiveRecord { public function __construct($conexão_banco_de_dados) { // você pode defini-la assim parent::__construct($conexão_banco_de_dados, 'users'); // ou desta forma parent::__construct($conexão_banco_de_dados, null, [ 'table' => 'users']); } }
Agora veja a mágica acontecer!
// para sqlite $conexão_banco_de_dados = new PDO('sqlite:test.db'); // isso é apenas um exemplo, provavelmente você usaria uma conexão de banco de dados real // para mysql $conexão_banco_de_dados = new PDO('mysql:host=localhost;dbname=test_db&charset=utf8bm4', 'nome_de_usuário', 'senha'); // ou mysqli $conexão_banco_de_dados = new mysqli('localhost', 'nome_de_usuário', 'senha', 'test_db'); // ou mysqli com criação não baseada em objeto $conexão_banco_de_dados = mysqli_connect('localhost', 'nome_de_usuário', 'senha', 'test_db'); $user = new User($conexão_banco_de_dados); $user->name = 'Bobby Tables'; $user->password = password_hash('alguma senha legal'); $user->insert(); // ou $user->save(); echo $user->id; // 1 $user->name = 'Joseph Mamma'; $user->password = password_hash('outra senha legal novamente!!!'); $user->insert(); // não é possível usar $user->save() aqui senão pensará que é uma atualização! echo $user->id; // 2
E foi tão fácil adicionar um novo usuário! Agora que há uma linha de usuário no banco de dados, como você a extrai?
$user->find(1); // encontre id = 1 no banco de dados e retorne echo $user->name; // 'Bobby Tables'
E se você quiser encontrar todos os usuários?
$users = $user->findAll();
E com uma determinada condição?
$users = $user->like('name', '%mamma%')->findAll();
Veja como isso é divertido? Vamos instalar e começar!
Basta instalar com o Composer
composer require flightphp/active-record
Isso pode ser usado como uma biblioteca independente ou com o Framework PHP Flight. Totalmente com você.
Apenas certifique-se de passar uma conexão PDO para o construtor.
$conexão_pdo = new PDO('sqlite:test.db'); // isso é apenas um exemplo, provavelmente você usaria uma conexão de banco de dados real $User = new User($conexão_pdo);
Não quer sempre definir sua conexão de banco de dados no construtor? Veja Gerenciamento de Conexão de Banco de Dados para outras ideias!
Se estiver usando o Framework PHP Flight, você pode registrar a classe ActiveRecord como serviço, mas honestamente não precisa.
Flight::register('user', 'User', [ $conexão_pdo ]); // e então você pode usar assim em um controlador, uma função, etc. Flight::user()->find(1);
runway
runway é uma ferramenta CLI para o Flight que possui um comando personalizado para esta biblioteca.
# Uso php runway make:record nome_tabela_banco_dados [nome_classe] # Exemplo php runway make:record users
Isso criará uma nova classe no diretório app/records/ como UserRecord.php com o seguinte conteúdo:
UserRecord.php
<?php declare(strict_types=1); namespace app\records; /** * Classe ActiveRecord para a tabela de usuários. * @link https://docs.flightphp.com/awesome-plugins/active-record * * @property int $id * @property string $username * @property string $email * @property string $password_hash * @property string $created_dt */ class UserRecord extends \flight\ActiveRecord { /** * @var array $relations Define os relacionamentos para o modelo * https://docs.flightphp.com/awesome-plugins/active-record#relationships */ protected array $relations = [ // 'nome_relacao' => [ self::HAS_MANY, 'ClasseRelacionada', 'chave_estrang.'], ]; /** * Constructor * @param mixed $databaseConnection A conexão com o banco de dados */ public function __construct($databaseConnection) { parent::__construct($databaseConnection, 'users'); } }
find($id = null) : boolean|ActiveRecord
Encontre um registro e o atribua ao objeto atual. Se você passar um $id de algum tipo, ele fará uma busca na chave primária com esse valor. Se nada for passado, encontrará apenas o primeiro registro na tabela.
Além disso, você pode passar outros métodos auxiliares para consultar sua tabela.
// encontrar um registro com algumas condições antecipadas $user->notNull('password')->orderBy('id DESC')->find(); // encontrar um registro por um id específico $id = 123; $user->find($id);
findAll(): array<int,ActiveRecord>
Encontra todos os registros na tabela que você especificar.
$user->findAll();
isHydrated(): boolean
Retorna true se o registro atual foi hidratado (obtido do banco de dados).
$user->find(1); // se um registro for encontrado com dados... $user->isHydrated(); // true
insert(): boolean|ActiveRecord
Insere o registro atual no banco de dados.
$user = new User($conexão_banco_de_dados); $user->name = 'demo'; $user->password = md5('demo'); $user->insert();
Se você tiver uma chave primária baseada em texto (como um UUID), você pode definir o valor da chave primária antes de inserir de duas maneiras.
$user = new User($conexão_banco_de_dados, [ 'primaryKey' => 'uuid' ]); $user->uuid = 'some-uuid'; $user->name = 'demo'; $user->password = md5('demo'); $user->insert(); // ou $user->save();
ou você pode ter a chave primária gerada automaticamente para você por meio de eventos.
class User extends flight\ActiveRecord { public function __construct($conexão_banco_de_dados) { parent::__construct($conexão_banco_de_dados, 'users', [ 'primaryKey' => 'uuid' ]); // você também pode definir a chave primária assim em vez do array acima. $this->primaryKey = 'uuid'; } protected function beforeInsert(self $self) { $self->uuid = uniqid(); // ou como você precisa gerar seus ids únicos } }
Se você não definir a chave primária antes de inserir, ela será definida como o rowid e o banco de dados a gerará para você, mas não será persistida porque esse campo pode não existir em sua tabela. É por isso que é recomendado usar o evento para lidar automaticamente com isso para você.
rowid
update(): boolean|ActiveRecord
Atualiza o registro atual no banco de dados.
$user->greaterThan('id', 0)->orderBy('id desc')->find(); $user->email = 'test@example.com'; $user->update();
save(): boolean|ActiveRecord
Insere ou atualiza o registro atual no banco de dados. Se o registro tiver um id, ele atualizará, caso contrário, ele inserirá.
$user = new User($conexão_banco_de_dados); $user->name = 'demo'; $user->password = md5('demo'); $user->save();
Nota: Se você tiver relacionamentos definidos na classe, ele salvará recursivamente essas relações também se elas tiverem sido definidas, instanciadas e tiverem dados sujos para atualizar. (v0.4.0 e acima)
delete(): boolean
Exclui o registro atual do banco de dados.
$user->gt('id', 0)->orderBy('id desc')->find(); $user->delete();
Você também pode excluir vários registros executando uma busca antes.
$user->like('name', 'Bob%')->delete();
dirty(array $dirty = []): ActiveRecord
Dados sujos se referem aos dados que foram alterados em um registro.
$user->greaterThan('id', 0)->orderBy('id desc')->find(); // nada está "sujo" até este ponto. $user->email = 'test@example.com'; // agora o email é considerado "sujo" porque foi alterado. $user->update(); // agora não há dados sujos porque foram atualizados e persistidos no banco de dados $user->password = password_hash()'nova senha'); // agora isso é sujo $user->dirty(); // passando nada limpará todas as entradas sujas. $user->update(); // nada será atualizado porque nada foi considerado sujo. $user->dirty([ 'name' => 'algo', 'password' => password_hash('uma senha diferente') ]); $user->update(); // tanto o nome quanto a senha são atualizados.
copyFrom(array $data): ActiveRecord
Isso é um alias para o método dirty(). É um pouco mais claro o que você está fazendo.
dirty()
$user->copyFrom([ 'name' => 'algo', 'password' => password_hash('uma senha diferente') ]); $user->update(); // tanto o nome quanto a senha são atualizados.
isDirty(): boolean
Retorna true se o registro atual foi alterado.
$user->greaterThan('id', 0)->orderBy('id desc')->find(); $user->email = 'test@email.com'; $user->isDirty(); // true
reset(bool $include_query_data = true): ActiveRecord
Redefine o registro atual para seu estado inicial. Isso é realmente útil para usar em comportamentos de loop. Se você passar true, também redefinirá os dados da consulta que foram usados para encontrar o objeto atual (comportamento padrão).
$users = $user->greaterThan('id', 0)->orderBy('id desc')->find(); $user_company = new UserCompany($conexão_banco_de_dados); foreach($users as $user) { $user_company->reset(); // comece com uma tela limpa $user_company->user_id = $user->id; $user_company->company_id = $some_company_id; $user_company->insert(); }
getBuiltSql(): string
Depois de executar um método find(), findAll(), insert(), update() ou save(), você pode obter o SQL que foi construído e usá-lo para fins de depuração.
find()
findAll()
insert()
update()
save()
select(string $campo1 [, string $campo2 ... ])
Você pode selecionar apenas alguns dos campos em uma tabela, se desejar (é mais eficiente em tabelas realmente largas com muitas colunas)
$user->select('id', 'name')->find();
from(string $tabela)
Você tecnicamente pode escolher outra tabela também! Por que não?!
$user->select('id', 'name')->from('user')->find();
join(string $nome_tabela, string $condição_junção)
Você pode até juntar-se a outra tabela no banco de dados.
$user->join('contatos', 'contatos.user_id = users.id')->find();
where(string $condições_where)
Você pode definir alguns argumentos where personalizados (você não pode definir parâmetros nesta declaração where)
$user->where('id=1 AND name="demo"')->find();
Nota de Segurança - Você pode ser tentado a fazer algo como $user->where("id = '{$id}' AND name = '{$name}'")->find();. Por favor, NÃO FAÇA ISSO!!! Isso é susceptível a ataques de injeção de SQL. Há muitos artigos online, por favor, procure por "e...
$user->where("id = '{$id}' AND name = '{$name}'")->find();
Latte é um mecanismo de modelo completo que é muito fácil de usar e se sente mais próximo de uma sintaxe PHP do que Twig ou Smarty. Também é muito fácil de estender e adicionar seus próprios filtros e funções.
composer require latte/latte
Existem algumas opções de configuração básicas para começar. Você pode ler mais sobre elas na Documentação do Latte.
use Latte\Engine as LatteEngine; require 'vendor/autoload.php'; $app = Flight::app(); $app->register('latte', LatteEngine::class, [], function(LatteEngine $latte) use ($app) { // Aqui é onde o Latte irá armazenar em cache seus modelos para acelerar as coisas // Uma coisa legal sobre o Latte é que ele atualiza automaticamente seu // cache quando você faz alterações nos seus modelos! $latte->setTempDirectory(__DIR__ . '/../cache/'); // Diga ao Latte onde o diretório raiz para suas visualizações estará // $app->get('flight.views.path') é definido no arquivo config.php // Você também pode fazer algo como `__DIR__ . '/../views/'` $latte->setLoader(new \Latte\Loaders\FileLoader($app->get('flight.views.path'))); });
Aqui está um exemplo simples de um arquivo de layout. Este é o arquivo que será usado para envolver todas as suas outras visualizações.
<!-- app/views/layout.latte --> <!doctype html> <html lang="en"> <head> <title>{$title ? $title . ' - '}My App</title> <link rel="stylesheet" href="style.css"> </head> <body> <header> <nav> <!-- seus elementos de navegação aqui --> </nav> </header> <div id="content"> <!-- Aqui está a mágica --> {block content}{/block} </div> <div id="footer"> © Direitos autorais </div> </body> </html>
E agora temos seu arquivo que será renderizado dentro desse bloco de conteúdo:
<!-- app/views/home.latte --> <!-- Isso diz ao Latte que este arquivo está "dentro" do arquivo layout.latte --> {extends layout.latte} <!-- Este é o conteúdo que será renderizado dentro do layout dentro do bloco de conteúdo --> {block content} <h1>Página Inicial</h1> <p>Bem-vindo ao meu aplicativo!</p> {/block}
Então, quando você for renderizar isso dentro da sua função ou controlador, você faria algo assim:
// rota simples Flight::route('/', function () { Flight::latte()->render('home.latte', [ 'title' => 'Página Inicial' ]); }); // ou se estiver usando um controlador Flight::route('/', [HomeController::class, 'index']); // HomeController.php class HomeController { public function index() { Flight::latte()->render('home.latte', [ 'title' => 'Página Inicial' ]); } }
Veja a Documentação do Latte para mais informações sobre como usar o Latte em todo o seu potencial!
Flight é incrivelmente extensível. Existem vários plugins que podem ser usados para adicionar funcionalidades à sua aplicação Flight. Alguns são oficialmente suportados pela Equipe do Flight e outros são bibliotecas micro/lite para ajudá-lo a começar.
A autenticação e autorização são cruciais para qualquer aplicação que requer controles para determinar quem pode acessar o quê.
O armazenamento em cache é uma ótima maneira de acelerar sua aplicação. Existem várias bibliotecas de armazenamento em cache que podem ser usadas com o Flight.
Aplicações CLI são uma ótima maneira de interagir com sua aplicação. Você pode usá-las para gerar controladores, exibir todas as rotas e muito mais.
Cookies são uma ótima maneira de armazenar pequenos pedaços de dados no lado do cliente. Eles podem ser usados para armazenar preferências do usuário, configurações da aplicação e muito mais.
A depuração é crucial ao desenvolver em seu ambiente local. Existem alguns plugins que podem aprimorar sua experiência de depuração.
Bancos de dados são essenciais para a maioria das aplicações. É assim que você armazena e recupera dados. Algumas bibliotecas de banco de dados são simplesmente wrappers para escrever consultas e outras são ORMs completos.
Criptografia é crucial para qualquer aplicação que armazena dados sensíveis. Criptografar e descriptografar os dados não é tão difícil, mas armazenar corretamente a chave de criptografia pode ser difícil. A coisa mais importante é nunca armazenar sua chave de criptografia em um diretório público ou commitá-la em seu repositório de código.
As sessões não são realmente úteis para APIs, mas para o desenvolvimento de aplicações web, as sessões podem ser cruciais para manter o estado e as informações de login.
A modelagem é essencial para qualquer aplicação web com uma UI. Existem várias engines de modelagem que podem ser usadas com o Flight.
Tem um plugin que você gostaria de compartilhar? Envie um pull request para adicioná-lo à lista!
Tentamos rastrear o que podemos dos vários tipos de mídia pela internet sobre o Flight. Veja abaixo diferentes recursos que você pode usar para aprender mais sobre o Flight.
Você tem duas opções para começar com o Flight:
Embora esses não sejam oficialmente patrocinados pela equipe do Flight, eles podem te dar ideias sobre como estruturar seus próprios projetos construídos com o Flight!
Se você tem um projeto que deseja compartilhar, envie um pull request para adicioná-lo a esta lista!
Certifique-se de ter o PHP instalado em seu sistema. Caso contrário, clique aqui para obter instruções sobre como instalá-lo em seu sistema.
Se estiver usando Composer, você pode executar o seguinte comando:
OU você pode baixar os arquivos diretamente e extrair para o diretório da web.
Esta é de longe a maneira mais simples de começar. Você pode usar o servidor integrado para executar sua aplicação e até mesmo usar SQLite para um banco de dados (desde que o sqlite3 esteja instalado em seu sistema) e não exigir muito! Basta executar o seguinte comando uma vez que o PHP estiver instalado:
php -S localhost:8000
Em seguida, abra seu navegador e vá para http://localhost:8000.
http://localhost:8000
Se quiser definir o diretório raiz do seu projeto como um diretório diferente (Por ex: seu projeto é ~/myproject, mas sua raiz do documento é ~/myproject/public/), você pode executar o seguinte comando uma vez que estiver no diretório ~/myproject:
~/myproject
~/myproject/public/
php -S localhost:8000 -t public/
Então, abra seu navegador e vá para http://localhost:8000.
Certifique-se de que o Apache já esteja instalado em seu sistema. Caso contrário, pesquise como instalar o Apache em seu sistema.
Para o Apache, edite seu arquivo .htaccess com o seguinte:
Nota: Se precisar usar o flight em um subdiretório, adicione a linha RewriteBase /subdir/ logo após RewriteEngine On. Nota: Se desejar proteger todos os arquivos do servidor, como um arquivo db ou env. Coloque isso em seu arquivo .htaccess:
Nota: Se precisar usar o flight em um subdiretório, adicione a linha RewriteBase /subdir/ logo após RewriteEngine On.
Nota: Se desejar proteger todos os arquivos do servidor, como um arquivo db ou env. Coloque isso em seu arquivo .htaccess:
Certifique-se de que o Nginx já esteja instalado em seu sistema. Caso contrário, pesquise como instalar o Nginx em seu sistema.
<?php // Se estiver usando o Composer, requer o autoloader. require 'vendor/autoload.php'; // se não estiver usando o Composer, carregue o framework diretamente // require 'flight/Flight.php'; // Em seguida, defina uma rota e atribua uma função para lidar com a solicitação. Flight::route('/', function () { echo 'olá mundo!'; }); // Por fim, inicie o framework. Flight::start();
Se você já tem o php instalado em seu sistema, vá em frente e pule estas instruções e vá para a seção de download
php
Claro! Aqui estão as instruções para instalar o PHP no macOS, Windows 10/11, Ubuntu e Rocky Linux. Também incluirei detalhes sobre como instalar diferentes versões do PHP.
Instalar o Homebrew (caso ainda não esteja instalado):
/bin/bash -c "$(curl -fsSL https://raw.githubusercontent.com/Homebrew/install/HEAD/install.sh)"
Instalar o PHP:
brew install php
brew tap shivammathur/php brew install shivammathur/php/php@8.1
Alternar entre versões do PHP:
brew unlink php brew link --overwrite --force php@8.1
php -v
Baixar o PHP:
Extrair o PHP:
C:\php
Adicionar o PHP ao PATH do sistema:
Configurar o PHP:
php.ini-development
php.ini
extension_dir
Verificar a instalação do PHP:
Repita os passos acima para cada versão, colocando cada uma em um diretório separado (por ex., C:\php7, C:\php8).
C:\php7
C:\php8
Alternar entre as versões ajustando a variável PATH do sistema para apontar para o diretório da versão desejada.
Atualizar listas de pacotes:
sudo apt update
sudo apt install php
sudo apt install php8.1
Instalar módulos adicionais (opcional):
sudo apt install php8.1-mysql
Alternar entre as versões do PHP:
update-alternatives
sudo update-alternatives --set php /usr/bin/php8.1
Verificar a versão instalada:
Ativar o repositório EPEL:
sudo dnf install epel-release
Instalar o repositório do Remi:
sudo dnf install https://rpms.remirepo.net/enterprise/remi-release-8.rpm sudo dnf module reset php
sudo dnf install php
sudo dnf module install php:remi-7.4
dnf
sudo dnf module reset php sudo dnf module enable php:remi-8.0 sudo dnf install php