Uma microestrutura PHP poderosa, mas fácil de usar, projetada para ajudá-lo a construir aplicativos Web dinâmicos e robustos - rápido!
Condensado em um único arquivo de aproximadamente 65 KB, F3 (como carinhosamente o chamamos) oferece uma base sólida, uma base de código madura e uma abordagem prática para escrever aplicativos da Web. Nos bastidores está um kit de ferramentas de desenvolvimento Web fácil de usar, um mecanismo de cache e roteamento de URL de alto desempenho, realce de código integrado e suporte para aplicativos multilíngues. É leve, fácil de usar e rápido. Acima de tudo, isso não atrapalha seu caminho.
Quer você seja um programador PHP novato ou especialista, o F3 o colocará em funcionamento rapidamente. Sem procedimentos de instalação desnecessários e meticulosos. Nenhuma configuração complexa necessária. Nenhuma estrutura de diretório complicada. Não há melhor momento para começar a desenvolver aplicações Web de maneira fácil do que agora!
F3 oferece suporte a bancos de dados SQL e NoSQL prontos para uso: MySQL, SQLite, MSSQL/Sybase, PostgreSQL, DB2 e MongoDB. Ele também vem com mapeadores objeto-relacionais poderosos para abstração e modelagem de dados que são tão leves quanto a estrutura. Nenhuma configuração necessária.
Isso não é tudo. F3 vem com outros plug-ins opcionais que ampliam seus recursos:-
Ao contrário de outros frameworks, o F3 pretende ser utilizável – o que não é comum.
A filosofia por trás da estrutura e sua abordagem à arquitetura de software é voltada para o minimalismo nos componentes estruturais, evitando a complexidade da aplicação e alcançando um equilíbrio entre elegância do código, desempenho da aplicação e produtividade do programador.
F3 possui uma arquitetura de classe empresarial estável. Desempenho imbatível, recursos fáceis de usar e tamanho leve. O que mais você pode pedir? Para obter este pacote, basta baixá-lo ou visitar o repositório fatfree-core para encontrar a versão mais recente do edge.
Para todos os usuários do compositor:
composer create-project bcosca/fatfree
composer require bcosca/fatfree-core
É altamente recomendável que usuários experientes desenvolvam novos aplicativos com a versão mais recente para aproveitar uma base de código atualizada e melhorias contínuas.
O guia do usuário mais atualizado e a documentação detalhada da API com muitos exemplos de código e um guia gráfico podem ser encontrados em fatfreeframework.com/.
É claro que esta útil referência online é desenvolvida pela F3! Ele mostra a capacidade e o desempenho da estrutura. Confira agora. Se quiser lê-lo diretamente no github, você pode encontrar o conteúdo do site em github.com/F3Community/F3com-data
Um designer sabe que alcançou a perfeição não quando não há mais nada a acrescentar, mas quando não há mais nada a retirar. -Antoine de Saint-Exupéry
O Fat-Free Framework facilita a construção de sites inteiros em um instante. Com o mesmo poder e brevidade dos modernos kits de ferramentas e bibliotecas Javascript, F3 ajuda você a escrever programas PHP mais bonitos e confiáveis. Uma olhada em seu código-fonte PHP e qualquer pessoa achará fácil entender o quanto você pode realizar em tão poucas linhas de código e quão poderosos são os resultados.
F3 é um dos frameworks mais bem documentados que existe. Aprender isso custa quase nada. Nenhum conjunto estrito de estruturas de diretório difíceis de navegar e etapas de programação intrusivas. Não há muitas opções de configuração apenas para exibir 'Hello, World'
em seu navegador. Fat-Free oferece muita liberdade - e estilo - para realizar mais trabalhos com facilidade e em menos tempo.
A abordagem declarativa da F3 para programação facilita tanto para novatos quanto para especialistas entender o código PHP. Se você estiver familiarizado com a linguagem de programação Ruby, notará a semelhança entre a microestrutura Fat-Free e Sinatra porque ambos empregam uma linguagem simples de domínio específico para serviços da Web ReSTful. Mas, diferentemente do Sinatra e de suas encarnações PHP (Fitzgerald, Limonade, Glue – para citar alguns), o Fat-Free vai além de apenas lidar com rotas e solicitações. As visualizações podem estar em qualquer formato, como texto simples, HTML, XML ou uma mensagem de email. A estrutura vem com um mecanismo de modelo rápido e fácil de usar. F3 também funciona perfeitamente com outros mecanismos de modelo, incluindo Twig, Smarty e o próprio PHP. Os modelos se comunicam com os mapeadores de dados do F3 e com o auxiliar SQL para interações mais complexas com vários mecanismos de banco de dados. Outros plug-ins ampliam ainda mais a funcionalidade básica. É uma estrutura total de desenvolvimento Web - com muita força!
Descompacte o conteúdo do pacote de distribuição em qualquer lugar do seu disco rígido. Por padrão, o arquivo da estrutura e os plug-ins opcionais estão localizados no caminho lib/
. Organize suas estruturas de diretórios da maneira que desejar. Você pode mover as pastas padrão para um caminho que não seja acessível pela Web para maior segurança. Exclua os plug-ins desnecessários. Você sempre pode restaurá-los mais tarde e F3 detectará sua presença automaticamente.
Importante: Se seu aplicativo usa APC, Memcached, WinCache, XCache ou um cache de sistema de arquivos, limpe todas as entradas de cache antes de substituir uma versão mais antiga da estrutura por uma nova.
Certifique-se de estar executando a versão correta do PHP. F3 não suporta versões anteriores ao PHP 7.2. Você receberá erros de sintaxe (falsos positivos) em todos os lugares porque novas construções de linguagem e fechamentos/funções anônimas não são suportadas por versões desatualizadas do PHP. Para descobrir, abra seu console ( bash
shell no GNU/Linux ou cmd.exe
no Windows): –
/path/to/php -v
O PHP informará qual versão específica você está executando e você deverá obter algo semelhante a isto: –
PHP 7.4.21 (cli) (built: Jul 27 2021 15:56:07) ( NTS )
Copyright (c) The PHP Group
Zend Engine v3.4.0, Copyright (c) Zend Technologies
with Xdebug v2.9.8, Copyright (c) 2002-2020, by Derick Rethans
Atualize se necessário e volte aqui se você migrou para o PHP 7.4 ou uma versão posterior. Fatfree precisa de pelo menos PHP 7.2 para funcionar. Se você precisar de um provedor de serviços de hospedagem, experimente um destes serviços:
É hora de começar a escrever nossa primeira aplicação: -
$ f3 = require ( ' path/to/base.php ' );
$ f3 -> route ( ' GET / ' ,
function () {
echo ' Hello, world! ' ;
}
);
$ f3 -> run ();
Anexe base.php
na primeira linha com o caminho apropriado. Salve o fragmento de código acima como index.php
na pasta raiz da web. Escrevemos nossa primeira página Web.
Usando compositor? Em seguida, basta executar composer require bcosca/fatfree
e usar o seguinte:
require ' vendor/autoload.php ' ;
$ f3 = Base:: instance ();
$ f3 -> route ( ' GET / ' ,
function () {
echo ' Hello, world! ' ;
}
);
$ f3 -> run ();
O primeiro comando informa ao interpretador PHP que você deseja que as funções e recursos do framework estejam disponíveis para sua aplicação. O método $f3->route()
informa ao Fat-Free que uma página da Web está disponível na URL relativa indicada pela barra ( /
). Qualquer pessoa que visitar seu site localizado em http://www.example.com/
verá a mensagem 'Hello, world!'
mensagem porque o URL /
é equivalente à página raiz. Para criar uma rota que se ramifica a partir da página raiz, como http://www.example.com/inside/
, você pode definir outra rota com uma string GET /inside
simples.
A rota descrita acima informa ao framework para renderizar a página somente quando receber uma solicitação de URL usando o método HTTP GET
. Sites mais complexos contendo formulários usam outros métodos HTTP como POST
, e você também pode implementar isso como parte de uma especificação $f3->route()
.
Se a estrutura vir uma solicitação de entrada para sua página da Web localizada na URL raiz /
, ela encaminhará automaticamente a solicitação para a função de retorno de chamada, que contém o código necessário para processar a solicitação e renderizar o material HTML apropriado. Neste exemplo, apenas enviamos a string 'Hello, world!'
para o navegador da Web do usuário.
Então estabelecemos nossa primeira rota. Mas isso não adianta muito, exceto informar ao F3 que existe um processo que irá lidar com isso e que há algum texto para exibir no navegador da Web do usuário. Se você tiver muito mais páginas em seu site, será necessário configurar rotas diferentes para cada grupo. Por enquanto, vamos manter as coisas simples. Para instruir o framework a começar a esperar por solicitações, emitimos o comando $f3->run()
.
Não consegue executar o exemplo? Se você estiver tendo problemas para executar este programa simples em seu servidor, talvez seja necessário ajustar um pouco as configurações do servidor Web. Dê uma olhada no exemplo de configuração do Apache na seção a seguir (junto com os equivalentes Nginx e Lighttpd).
Ainda está tendo problemas? Certifique-se de $f3 = require('path/to/base.php');
a atribuição vem antes de qualquer saída em seu script. base.php
modifica os cabeçalhos HTTP, portanto, qualquer caractere enviado ao navegador antes desta atribuição causará erros.
Nosso primeiro exemplo não foi muito difícil de engolir, não é? Se você gosta de um pouco mais de sabor em sua sopa sem gordura, insira outra rota antes do comando $f3->run()
:-
$ f3 -> route ( ' GET /about ' ,
function () {
echo ' Donations go to a local charity... us! ' ;
}
);
Você não quer sobrecarregar o namespace global com nomes de funções? Fat-Free reconhece diferentes maneiras de mapear manipuladores de rotas para classes e métodos OOP: -
class WebPage {
function display () {
echo ' I cannot object to an object ' ;
}
}
$ f3 -> route ( ' GET /about ' , ' WebPage->display ' );
Solicitações HTTP também podem ser roteadas para métodos de classe estáticos: –
$ f3 -> route ( ' GET /login ' , ' Auth::login ' );
Argumentos passados são sempre fornecidos como segundo parâmetro:
$ f3 -> route ( ' GET /hello/@name ' , ' User::greet ' );
class User {
public static function greet ( $ f3 , $ args ) { // $ args is type of Array
echo " Hello " . $ args [ ' name ' ];
}
}
Se o argumento do nome fornecido fosse foo (/hello/foo), a seguinte saída seria mostrada:
Hello foo
Como uma demonstração da poderosa linguagem específica de domínio (DSL) do Fat-Free, você pode especificar uma única rota para lidar com diferentes possibilidades:-
$ f3 -> route ( ' GET /brew/@count ' ,
function ( $ f3 ) {
echo $ f3 -> get ( ' PARAMS.count ' ). ' bottles of beer on the wall. ' ;
}
);
Este exemplo mostra como podemos especificar um token @count
para representar parte de uma URL. A estrutura servirá qualquer URL de solicitação que corresponda ao prefixo /brew/
, como /brew/99
, /brew/98
, etc. Isso exibirá '99 bottles of beer on the wall'
e '98 bottles of beer on the wall'
, respectivamente. Fat-Free também aceitará uma solicitação de página para /brew/unbreakable
. (Espere que isso exiba 'unbreakable bottles of beer on the wall'
.) Quando tal rota dinâmica é especificada, o Fat-Free preenche automaticamente a variável de matriz global PARAMS
com o valor das strings capturadas na URL. A chamada $f3->get()
dentro da função de retorno de chamada recupera o valor de uma variável de estrutura. Você certamente pode aplicar esse método em seu código como parte da apresentação ou da lógica de negócios. Mas discutiremos isso com mais detalhes posteriormente.
Observe que o Fat-Free entende a notação de pontos de array. Você pode usar a notação regular PARAMS['count']
no código, o que é propenso a erros de digitação e colchetes desequilibrados. Em visualizações e modelos, a estrutura permite a notação @PARAMS.count
, que é um pouco semelhante ao Javascript. (Abordaremos visualizações e modelos mais tarde.)
Aqui está outra maneira de acessar tokens em um padrão de solicitação: –
$ f3 -> route ( ' GET /brew/@count ' ,
function ( $ f3 , $ params ) {
echo $ params [ ' count ' ]. ' bottles of beer on the wall. ' ;
}
);
Você pode usar o asterisco ( *
) para aceitar qualquer URL após a rota /brew
- se você realmente não se importa com o resto do caminho: -
$ f3 -> route ( ' GET /brew/* ' ,
function () {
echo ' Enough beer! We always end up here. ' ;
}
);
Um ponto importante a considerar: você ficará confuso com o Fat-Free (e com você mesmo) se tiver GET /brew/@count
e GET /brew/*
juntos no mesmo aplicativo. Use um ou outro. Outra coisa: Fat-Free vê GET /brew
como separado e distinto da rota GET /brew/@count
. Cada um pode ter manipuladores de rota diferentes.
Espere um segundo - em todos os exemplos anteriores, nunca criamos nenhum diretório em nosso disco rígido para armazenar essas rotas. A resposta curta: não precisamos. Todas as rotas F3 são virtuais. Eles não refletem a estrutura de pastas do disco rígido. Se você possui programas ou arquivos estáticos (imagens, CSS, etc.) que não utilizam o framework - desde que os caminhos para esses arquivos não entrem em conflito com nenhuma rota definida em sua aplicação - o software do seu servidor Web os entregará ao navegador do usuário, desde que o servidor esteja configurado corretamente.
Ao definir uma rota, você pode atribuir um nome a ela. Use o nome da rota em seu código e modelos em vez de um URL digitado. Então, se você precisar alterar suas URLs para agradar aos senhores do marketing, basta fazer a alteração onde a rota foi definida. Os nomes das rotas devem seguir as regras de nomenclatura de variáveis php (sem pontos, traços ou hífens).
Vamos nomear uma rota: -
$ f3 -> route ( ' GET @beer_list: /beer ' , ' Beer->list ' );
O nome é inserido após a rota VERB ( GET
neste exemplo) precedido por um símbolo @
e separado da parte do URL por dois pontos :
símbolo. Você pode inserir um espaço após os dois pontos se isso facilitar a leitura do seu código (como mostrado aqui).
Para acessar a rota nomeada em um modelo, obtenha o valor da rota nomeada como a chave do array hive ALIASES
:-
< a href =" {{ @ALIASES.beer_list }} " > View beer list </ a >
Para redirecionar o visitante para um novo URL, chame a rota nomeada dentro do método reroute()
como: –
// a named route is a string value
$ f3 -> reroute ( ' @beer_list ' ); // note the single quotes
Se você usar tokens em sua rota, F3 substituirá esses tokens pelo valor atual. Se você quiser alterar o valor do token antes de chamar o reroute, passe-o como o segundo argumento.:-
$ f3 -> route ( ' GET @beer_list: /beer/@country ' , ' Beer->bycountry ' );
$ f3 -> route ( ' GET @beer_list: /beer/@country/@village ' , ' Beer->byvillage ' );
// a set of key - value pairs is passed as argument to named route
$ f3 -> reroute ( ' @beer_list(@country=Germany) ' );
// if more than one token needed
$ f3 -> reroute ( ' @beer_list(@country=Germany,@village=Rhine) ' );
Lembre-se de urlencode()
seus argumentos se você tiver caracteres que não estejam em conformidade com as diretrizes da RFC 1738 para URLs bem formadas.
A versão estável mais recente do PHP possui seu próprio servidor Web integrado. Inicie usando a seguinte configuração: –
php -S localhost:80 -t /var/www/
O comando acima começará a rotear todas as solicitações para a raiz da Web /var/www
. Se uma solicitação HTTP de entrada para um arquivo ou pasta for recebida, o PHP irá procurá-la na raiz da Web e enviá-la ao navegador, se encontrada. Caso contrário, o PHP carregará o index.php
padrão (contendo seu código habilitado para F3).
Se você estiver usando o Apache, certifique-se de ativar o módulo de reescrita de URL (mod_rewrite) em seu arquivo apache.conf (ou httpd.conf). Você também deve criar um arquivo .htaccess contendo o seguinte: –
# Enable rewrite engine and route requests to framework
RewriteEngine On
# Some servers require you to specify the `RewriteBase` directive
# In such cases, it should be the path (relative to the document root)
# containing this .htaccess file
#
# RewriteBase /
RewriteRule ^(tmp)/|.ini$ - [R=404]
RewriteCond %{REQUEST_FILENAME} !-l
RewriteCond %{REQUEST_FILENAME} !-f
RewriteCond %{REQUEST_FILENAME} !-d
RewriteRule .* index.php [L,QSA]
RewriteRule .* - [E=HTTP_AUTHORIZATION:%{HTTP:Authorization},L]
O script informa ao Apache que sempre que uma solicitação HTTP chegar e se nenhum arquivo físico ( !-f
) ou caminho ( !-d
) ou link simbólico ( !-l
) puder ser encontrado, ele deverá transferir o controle para index.php
, que contém nosso controlador principal/frontal e que, por sua vez, invoca o framework.
O .htaccess file
contendo as diretivas do Apache indicadas acima deve estar sempre na mesma pasta que index.php
.
Você também precisa configurar o Apache para que ele saiba a localização física do index.php
no seu disco rígido. Uma configuração típica é: -
DocumentRoot " /var/www/html "
< Directory "/var/www/html">
Options -Indexes +FollowSymLinks +Includes
AllowOverride All
Order allow,deny
Allow from All
</ Directory >
Se você estiver desenvolvendo vários aplicativos simultaneamente, uma configuração de host virtual será mais fácil de gerenciar:-
NameVirtualHost *
< VirtualHost *>
ServerName site1.com
DocumentRoot " /var/www/site1 "
< Directory "/var/www/site1">
Options -Indexes +FollowSymLinks +Includes
AllowOverride All
Order allow,deny
Allow from All
</ Directory >
</ VirtualHost >
< VirtualHost *>
ServerName site2.com
DocumentRoot " /var/www/site2 "
< Directory "/var/www/site2">
Options -Indexes +FollowSymLinks +Includes
AllowOverride All
Order allow,deny
Allow from All
</ Directory >
</ VirtualHost >
Cada ServerName
( site1.com
e site2.com
em nosso exemplo) deve estar listado em seu arquivo /etc/hosts
. No Windows, você deve editar C:/WINDOWS/system32/drivers/etc/hosts
. Uma reinicialização pode ser necessária para efetuar as alterações. Você pode então apontar seu navegador da Web para o endereço http://site1.com
ou http://site2.com
. Os hosts virtuais tornam seus aplicativos muito mais fáceis de implantar.
Para servidores Nginx, aqui está a configuração recomendada (substitua ip_address:port pelas configurações FastCGI PHP do seu ambiente): –
server {
root /var/www/html;
location / {
index index.php index.html index.htm;
try_files $uri $uri / /index.php? $query_string ;
}
location ~ .php$ {
fastcgi_pass ip_address:port;
include fastcgi_params;
}
}
Os servidores Lighttpd são configurados de maneira semelhante: –
$HTTP["host"] =~ "www.example.com$" {
url.rewrite-once = ( "^/(.*?)(?.+)?$"=>"/index.php/$1?$2" )
server.error-handler-404 = "/index.php"
}
Instale o módulo de reescrita de URL e o framework .NET apropriado correspondente à sua versão do Windows. Em seguida, crie um arquivo chamado web.config
na raiz do seu aplicativo com o seguinte conteúdo:
<?xml version="1.0" encoding="UTF-8"?>
<configuration>
<system.webServer>
<rewrite>
<rules>
<rule name="Application" stopProcessing="true">
<match url=".*" ignoreCase="false" />
<conditions logicalGrouping="MatchAll">
<add input="{REQUEST_FILENAME}" matchType="IsFile" ignoreCase="false" negate="true" />
<add input="{REQUEST_FILENAME}" matchType="IsDirectory" ignoreCase="false" negate="true" />
</conditions>
<action type="Rewrite" url="index.php" appendQueryString="true" />
</rule>
</rules>
</rewrite>
</system.webServer>
</configuration>
Então, vamos voltar à codificação. Você pode declarar uma página obsoleta e redirecionar seus visitantes para outro site/página:-
$ f3 -> route ( ' GET|HEAD /obsoletepage ' ,
function ( $ f3 ) {
$ f3 -> reroute ( ' /newpage ' );
}
);
Se alguém tentar acessar a URL http://www.example.com/obsoletepage
usando uma solicitação HTTP GET ou HEAD, a estrutura redirecionará o usuário para a URL: http://www.example.com/newpage
conforme mostrado no exemplo exemplo acima. Você também pode redirecionar o usuário para outro site, como $f3->reroute('http://www.anotherexample.org/');
.
O redirecionamento pode ser particularmente útil quando você precisa fazer algum trabalho de manutenção em seu site. Você pode ter um gerenciador de rotas que informe aos visitantes que seu site ficará offline por um curto período.
Os redirecionamentos HTTP são indispensáveis, mas também podem ser caros. Tanto quanto possível, evite usar $f3->reroute()
para enviar um usuário para outra página no mesmo site se você puder direcionar o fluxo de seu aplicativo invocando a função ou método que trata a rota de destino. No entanto, esta abordagem não alterará o URL na barra de endereços do navegador da Web do usuário. Se este não for o comportamento que você deseja e você realmente precisar enviar um usuário para outra página, em casos como o envio bem-sucedido de um formulário ou após a autenticação de um usuário, o Fat-Free envia um cabeçalho HTTP 302 Found
. Para todas as outras tentativas de redirecionamento para outra página ou site, a estrutura envia um cabeçalho HTTP 301 Moved Permanently
.
Em tempo de execução, o Fat-Free gera automaticamente um erro HTTP 404 sempre que percebe que uma solicitação HTTP recebida não corresponde a nenhuma das rotas definidas em seu aplicativo. No entanto, há casos em que você mesmo precisa acioná-lo.
Tomemos, por exemplo, uma rota definida como GET /dogs/@breed
. A lógica do seu aplicativo pode envolver a pesquisa em um banco de dados e a tentativa de recuperar o registro correspondente ao valor de @breed
na solicitação HTTP recebida. Como o Fat-Free aceitará qualquer valor após o prefixo /dogs/
devido à presença do token @breed
, exibir uma mensagem HTTP 404 Not Found
programaticamente torna-se necessário quando o programa não encontra nenhuma correspondência em nosso banco de dados. Para fazer isso, use o seguinte comando: –
$ f3 -> error ( 404 );
A arquitetura do Fat-Free é baseada no conceito de que URIs HTTP representam recursos abstratos da Web (não limitados a HTML) e cada recurso pode passar de um estado de aplicativo para outro. Por esse motivo, F3 não possui nenhuma restrição na forma como você estrutura sua aplicação. Se você preferir usar o padrão Model-View-Controller, F3 pode ajudá-lo a compartimentar os componentes do seu aplicativo para seguir esse paradigma. Por outro lado, a estrutura também suporta o padrão Resource-Method-Representation, e implementá-lo é mais simples.
Aqui está um exemplo de interface ReST: –
class Item {
function get () {}
function post () {}
function put () {}
function delete () {}
}
$ f3 = require ( ' lib/base.php ' );
$ f3 -> map ( ' /cart/@item ' , ' Item ' );
$ f3 -> run ();
O método $f3->map()
do Fat-Free fornece uma interface ReST mapeando métodos HTTP em rotas para os métodos equivalentes de um objeto ou classe PHP. Se o seu aplicativo receber uma solicitação HTTP como GET /cart/123
, o Fat-Free transferirá automaticamente o controle para o método get()
do objeto ou da classe. Por outro lado, uma solicitação POST /cart/123
será roteada para o método post()
da classe Item
.
Nota: Os navegadores não implementam os métodos HTTP PUT
e DELETE
em formulários HTML regulares. Esses e outros métodos ReST ( HEAD
e CONNECT
) são acessíveis apenas por meio de chamadas AJAX ao servidor.
Se o framework receber uma solicitação HTTP para uma rota que mapeia para um método que não está implementado por uma classe (talvez você tenha cometido um erro no mapeamento da rota ou o método ainda não tenha sido escrito), ele gera um HTTP 405 Method Not Allowed
Erro HTTP 405 Method Not Allowed
.
Se um cliente solicitar OPTIONS
HTTP para um recurso URL, F3 responderá com os cabeçalhos HTTP apropriados que indicam quais métodos são permitidos para o recurso (HEAD, GET, PUT, etc). A estrutura não mapeará a solicitação OPTIONS
para uma classe.
Fat-Free tem uma maneira de carregar classes apenas no momento em que você precisa delas, para que elas não ocupem mais memória do que um segmento específico de seu aplicativo precisa. E você não precisa escrever uma longa lista de instruções include
ou require
apenas para carregar classes PHP salvas em diferentes arquivos e locais. A estrutura pode fazer isso automaticamente para você. Basta salvar seus arquivos (uma classe por arquivo) em uma pasta e dizer ao framework para carregar automaticamente o arquivo apropriado assim que você invocar um método na classe: –
$ f3 -> set ( ' AUTOLOAD ' , ' autoload/ ' );
Você pode atribuir um local diferente para suas classes carregadas automaticamente alterando o valor da variável global AUTOLOAD
. Você também pode ter vários caminhos de carregamento automático. Se você tiver suas classes organizadas e em pastas diferentes, poderá instruir a estrutura a carregar automaticamente a classe apropriada quando um método estático for chamado ou quando um objeto for instanciado. Modifique a variável AUTOLOAD
desta forma: –
$ f3 -> set ( ' AUTOLOAD ' , ' admin/autoload/; user/autoload/; default/ ' );
Importante: Exceto pela extensão .php, o nome da classe e o nome do arquivo devem ser idênticos, para que o framework carregue automaticamente sua classe corretamente. O nome base deste arquivo deve ser idêntico ao da invocação da sua classe, por exemplo, F3 irá procurar por Foo/BarBaz.php
ou foo/barbaz.php
quando detectar uma new FooBarBaz
em sua aplicação.
AUTOLOAD
permite que hierarquias de classes residam em subpastas com nomes semelhantes, portanto, se você deseja que a estrutura carregue automaticamente uma classe com namespace invocada da seguinte maneira: -
$ f3 -> set ( ' AUTOLOAD ' , ' autoload/ ' );
$ obj = new Gadgets iPad ;
Você pode criar uma hierarquia de pastas que siga a mesma estrutura. Supondo que /var/www/html/
seja a raiz da sua Web, F3 procurará a classe em /var/www/html/autoload/gadgets/ipad.php
. O arquivo ipad.php
deve ter o seguinte código mínimo: –
namespace Gadgets ;
class iPad {}
Lembre-se: todos os nomes de diretório no Fat-Free devem terminar com uma barra. Você pode atribuir um caminho de pesquisa para o autoloader da seguinte maneira: –
$ f3 -> set ( ' AUTOLOAD ' , ' main/;aux/ ' );
F3, sendo uma estrutura com reconhecimento de namespace, permite que você use um método em uma classe com namespace como um manipulador de rota, e há várias maneiras de fazer isso. Para chamar um método estático: –
$ f3 -> set ( ' AUTOLOAD ' , ' classes/ ' );
$ f3 -> route ( ' GET|POST / ' , ' MainHome::show ' );
O código acima invocará o método estático show()
da classe Home
dentro do namespace Main
. A classe Home
deve ser salva na pasta classes/main/home.php
para que seja carregada automaticamente.
Se você preferir trabalhar com objetos:-
$ f3 -> route ( ' GET|POST / ' , ' MainHome->show ' );
irá instanciar a classe Home
em tempo de execução e chamar o método show()
posteriormente.
F3 possui alguns ouvintes de eventos de roteamento que podem ajudá-lo a melhorar o fluxo e a estrutura das classes do controlador. Digamos que você tenha uma rota definida da seguinte forma: -
$ f3 -> route ( ' GET / ' , ' Main->home ' );
Se a aplicação receber uma solicitação HTTP correspondente à rota acima, F3 instancia Main
, mas antes de executar o método home()
, a estrutura procura um método nesta classe chamado beforeRoute()
. Caso seja encontrado, F3 executa o código contido no manipulador de eventos beforeRoute()
antes de transferir o controle para o método home()
. Feito isso, a estrutura procura um manipulador de eventos afterRoute()
. Assim como beforeRoute()
, o método será executado se estiver definido.
Aqui está outra novidade do F3: -
$ f3 -> route ( ' GET /products/@action ' , ' Products->@action ' );
Se seu aplicativo receber uma solicitação de, digamos, /products/itemize
, F3 extrairá a string 'itemize'
da URL e a transmitirá ao token @action
no manipulador de rota. F3 irá então procurar uma classe chamada Products
e executar o método itemize()
.
Os manipuladores de rotas dinâmicas podem ter vários formatos: -
// static method
$ f3 -> route ( ' GET /public/@genre ' , ' Main::@genre ' );
// object mode
$ f3 -> route ( ' GET /public/@controller/@action ' , ' @controller->@action ' );
F3 aciona um erro HTTP 404 Not Found
em tempo de execução se não puder transferir o controle para a classe ou método associado à rota atual, ou seja, uma classe ou método indefinido.
Os padrões de roteamento podem conter modificadores que direcionam a estrutura para basear sua decisão de roteamento no tipo de solicitação HTTP:-
$ f3 -> route ( ' GET /example [ajax] ' , ' Page->getFragment ' );
$ f3 -> route ( ' GET /example [sync] ' , ' Page->getFull ' );
A primeira instrução roteará a solicitação HTTP para o retorno de chamada Page->getFragment()
somente se um cabeçalho X-Requested-With: XMLHttpRequest
(objeto AJAX) for recebido pelo servidor. Se uma solicitação comum (síncrona) for detectada, F3 simplesmente irá para o próximo padrão correspondente e, neste caso, executará o retorno de chamada Page->getFull()
.
Se nenhum modificador for definido em um padrão de roteamento, ambos os tipos de solicitação AJAX e síncrona serão roteados para o manipulador especificado.
Modificadores de padrão de rota também são reconhecidos por $f3->map()
.
As variáveis definidas no Fat-Free são globais, ou seja, podem ser acessadas por qualquer componente MVC. Os globais da estrutura não são idênticos aos globais do PHP. Uma variável F3 chamada content
não é idêntica à $content
do PHP. F3 é uma linguagem específica de domínio por si só e mantém sua própria tabela de símbolos separada para variáveis de sistema e de aplicativo. O framework, como todo programa orientado a objetos bem projetado, não polui o namespace global do PHP com constantes, variáveis, funções ou classes que possam entrar em conflito com qualquer aplicação. Ao contrário de outros frameworks, F3 não usa a instrução define()
do PHP. Todas as constantes da estrutura estão confinadas às classes.
Para atribuir um valor a uma variável Fat-Free:
$ f3 -> set ( ' var ' ,value); // or
$ f3 -> var =value;
$ f3 -> set ( ' hello.world ' , ' good morning ' ); // translates to : 'hello' == array ( 'world' = > 'good morning' )
$ f3 ->{ ' hello.world ' }= ' good morning ' ; // same as prior statement
Nota: Variáveis Fat-Free aceitam todos os tipos de dados PHP, incluindo objetos e funções anônimas.
Para definir diversas variáveis de uma vez:
$ f3 -> mset (
[
' foo ' => ' bar ' ,
' baz ' => 123
]
);
Para recuperar o valor de uma variável de estrutura chamada var
: –
echo $ f3 -> get ( ' var ' ); // or
echo $ f3 -> var ;
Para remover uma variável Fat-Free da memória se você não precisar mais dela (descarte-a para que não interfira em suas outras funções/métodos), use o método: –
$ f3 -> clear ( ' var ' ); // or
unset( $ f3 -> var );
Para descobrir se uma variável foi definida anteriormente: -
$ f3 -> exists ( ' var ' ) //
isset ( $ f3 -> var )
F3 mantém sua própria tabela de símbolos para variáveis de framework e aplicação, que são independentes do PHP. Algumas variáveis são mapeadas para globais do PHP. SESSION
do Fat-Free é equivalente a $_SESSION
e REQUEST
mapeia para $_REQUEST
. Recomenda-se o uso de variáveis de estrutura, em vez de PHP, para ajudá-lo na transferência de dados entre diferentes funções, classes e métodos. Eles também têm outras vantagens: -
SESSION
também altera o $_SESSION
subjacente do PHP. Alterar este último também altera a contrapartida do quadro. Fat-Free não mantém apenas um armazenamento burro para variáveis e seus valores. Também pode automatizar o gerenciamento de sessões e outras coisas. Atribuir ou recuperar um valor por meio da variável SESSION
de F3 inicia automaticamente a sessão. Se você usar $_SESSION
(ou funções relacionadas à sessão) diretamente, em vez da variável de estrutura SESSION
, seu aplicativo se tornará responsável pelo gerenciamento de sessões.
Via de regra, as variáveis de estrutura não persistem entre as solicitações HTTP. Somente SESSION
e COOKIE
(e seus elementos) que são mapeados para as variáveis globais $_SESSION
e $_COOKIE
do PHP estão isentos da natureza sem estado do HTTP.
Existem diversas variáveis globais predefinidas usadas internamente pelo Fat-Free, e você certamente pode utilizá-las em sua aplicação. Certifique-se de saber o que está fazendo. A alteração de algumas variáveis globais do Fat-Free pode resultar em comportamento inesperado da estrutura.
A estrutura possui diversas variáveis para ajudá-lo a manter seus arquivos e estruturas de diretórios organizados. Vimos como podemos automatizar o carregamento de classes usando AUTOLOAD
. Há uma variável global UI
, que contém o caminho que aponta para o local de suas visualizações/modelos HTML. DEBUG
é outra variável que você usará com frequência durante o desenvolvimento de aplicativos e é usada para definir o detalhamento dos rastreamentos de erros.
Consulte a Referência rápida se precisar de uma lista abrangente de variáveis de estrutura integradas.
Uma variável de estrutura pode conter qualquer número de letras, dígitos e sublinhados. Deve começar com um caractere alfabético e não deve conter espaços. Os nomes das variáveis diferenciam maiúsculas de minúsculas.
F3 usa letras maiúsculas para variáveis globais predefinidas internas. Nada impede você de usar nomes de variáveis com letras maiúsculas em seu próprio programa, mas como regra geral, use letras minúsculas (ou camelCase) ao configurar suas próprias variáveis, para evitar qualquer possível conflito com versões atuais e futuras da estrutura. .
Você não deve usar palavras reservadas do PHP como if
, for
, class
, default
, etc. como nomes de variáveis de framework. Isso pode causar resultados imprevisíveis.
F3 também fornece diversas ferramentas para ajudá-lo com variáveis de estrutura.
$ f3 -> set ( ' a ' , ' fire ' );
$ f3 -> concat ( ' a ' , ' cracker ' );
echo $ f3 -> get ( ' a ' ); // returns the string 'firecracker'
$ f3 -> copy ( ' a ' , ' b ' );
echo $ f3 -> get ( ' b ' ); // returns the same string : 'firecracker'
F3 também fornece alguns métodos primitivos para trabalhar com variáveis de array:-
$ f3 -> set ( ' colors ' ,[ ' red ' , ' blue ' , ' yellow ' ]);
$ f3 -> push ( ' colors ' , ' green ' ); // works like PHP ' s array_push ()
echo $ f3 -> pop ( ' colors ' ); // returns 'green'
$ f3 -> unshift ( ' colors ' , ' purple ' ); // similar to array_unshift ()
echo $ f3 -> shift ( ' colors ' ); // returns 'purple'
$ f3 -> set ( ' grays ' ,[ ' light ' , ' dark ' ]);
$ result = $ f3 -> merge ( ' colors ' , ' grays ' ); // merges the two arrays
Ao contrário de outras estruturas que possuem estruturas de pastas rígidas, F3 oferece muita flexibilidade. Você pode ter uma estrutura de pastas parecida com esta (palavras entre parênteses em letras maiúsculas representam as variáveis da estrutura F3 que precisam de ajustes): -
/ (your Web root, where index.php is located)
app/ (application files)
dict/ (LOCALES, optional)
controllers/
logs/ (LOGS, optional)
models/
views/ (UI)
css/
js/
lib/ (you can store base.php here)
tmp/ (TEMP, used by the framework)
cache/ (CACHE)
Sinta-se à vontade para organizar seus arquivos e diretórios da maneira que desejar. Basta definir as variáveis globais F3 apropriadas. Se você deseja um site realmente seguro, o Fat-Free ainda permite armazenar todos os seus arquivos em um diretório não acessível pela Web. O único requisito é que você deixe index.php
, .htaccess
e seus arquivos públicos, como CSS, JavaScript, imagens, etc. em um caminho visível para seu navegador.
Fat-Free gera suas próprias páginas de erro HTML, com rastreamentos de pilha para ajudá-lo na depuração. Aqui está um exemplo: -
Erro do Servidor Interno
strpos() espera pelo menos 2 parâmetros, 0 dado
• var/html/dev/main.php:96 strpos() • var/html/dev/index.php:16 Base->run()
Se você acha que é um pouco simples demais ou deseja fazer outras coisas quando o erro ocorre, você pode criar seu próprio manipulador de erros personalizado: –
$ f3 -> set ( ' ONERROR ' ,
function ( $ f3 ) {
// custom error handler code goes here
// use this if you want to display errors in a
// format consistent with your site ' s theme
echo $ f3 -> get ( ' ERROR.status ' );
}
);
F3 mantém uma variável global contendo os detalhes do último erro ocorrido em sua aplicação. A variável ERROR
é uma matriz estruturada da seguinte forma: -
ERROR.code - displays the error code (404, 500, etc.)
ERROR.status - header and page title
ERROR.text - error context
ERROR.trace - stack trace
Ao desenvolver seu aplicativo, é melhor definir o nível de depuração no máximo para que você possa rastrear todos os erros até sua causa raiz:-
$ f3 -> set ( ' DEBUG ' , 3 );
Basta inserir o comando na sequência de bootstrap da sua aplicação.
Quando seu aplicativo estiver pronto para lançamento, simplesmente remova a declaração do seu aplicativo ou substitua-a por: -
$ f3 -> set ( ' DEBUG ' , 0 );
Isso suprimirá a saída do rastreamento de pilha em qualquer página de erro HTML gerada pelo sistema (porque ela não deve ser vista pelos visitantes do site).
DEBUG
pode ter valores que variam de 0 (rastreamento de pilha suprimido) a 3 (mais detalhado).
Não se esqueça! Os rastreamentos de pilha podem conter caminhos, nomes de arquivos, comandos de banco de dados, nomes de usuários e senhas. Você poderá expor seu site a riscos de segurança desnecessários se não definir a variável global DEBUG
como 0 em um ambiente de produção.
Se o seu aplicativo precisar ser configurável pelo usuário, F3 fornece um método útil para ler arquivos de configuração para configurar seu aplicativo. Dessa forma, você e seus usuários podem ajustar o aplicativo sem alterar nenhum código PHP.
Em vez de criar um script PHP que contenha o seguinte código de exemplo:-
$ f3 -> set ( ' num ' , 123 );
$ f3 -> set ( ' str ' , ' abc ' );
$ f3 -> set ( ' hash ' ,[ ' x ' => 1 , ' y ' => 2 , ' z ' => 3 ]);
$ f3 -> set ( ' items ' ,[ 7 , 8 , 9 ]);
$ f3 -> set ( ' mix ' ,[ ' this ' , 123.45 , FALSE ]);
Você pode construir um arquivo de configuração que faça a mesma coisa: –
[globals]
num =123
; this is a regular string
str =abc
; another way of assigning strings
str = " abc "
; this is an array
hash[x]=1
hash[y]=2
hash[z]=3
; dot-notation is recognized too
hash.x =1
hash.y =2
hash.z =3
; this is also an array
items =7,8,9
; array with mixed elements
mix = " this " ,123.45,FALSE
Em vez de longas instruções $f3->set()
em seu código, você pode instruir a estrutura a carregar um arquivo de configuração como substituto do código. Vamos salvar o texto acima como setup.cfg. Podemos então chamá-lo com um simples: -
$ f3 -> config ( ' setup.cfg ' );
Os valores de string não precisam ser colocados entre aspas, a menos que você queira incluir espaços à esquerda ou à direita. Se uma vírgula deve ser tratada como parte de uma string, coloque a string entre aspas duplas - caso contrário, o valor será tratado como uma matriz (a vírgula é usada como um separador de elemento da matriz). As strings podem abranger várias linhas: -
[globals]
str = " this is a
very long
string "
F3 também oferece a capacidade de definir rotas HTTP em arquivos de configuração: –
[routes]
GET /=home
GET / 404 =App->page404
GET /page/@ num =Page->@controller
Os mapas de rotas também podem ser definidos em arquivos de configuração: –
[maps]
/ blog =BlogLogin
/blog/@ controller =Blog@controller
Os cabeçalhos das seções [globals]
, [routes]
e [maps]
são obrigatórios. Você pode combinar ambas as seções em um único arquivo de configuração - embora seja recomendado ter [routes]
e [maps]
em um arquivo separado. Dessa forma, você pode permitir que os usuários finais modifiquem alguns sinalizadores específicos do aplicativo e, ao mesmo tempo, impedi-los de interferir na sua lógica de roteamento.
Uma interface de usuário como uma página HTML deve ser independente do código PHP subjacente relacionado ao roteamento e à lógica de negócios. Isso é fundamental para o paradigma MVC. Uma revisão básica como a conversão de <h3>
para <p>
não deve exigir uma alteração no código da sua aplicação. Da mesma maneira, transformar uma rota simples como GET /about
em GET /about-us
não deve ter nenhum efeito na interface do usuário e na lógica de negócios (a visualização e o modelo no MVC ou a representação e o método no RMR).
Misturar construções de programação e componentes de interface do usuário em um único arquivo, como codificação espaguete, torna a manutenção futura de aplicativos um pesadelo.
F3 suporta o PHP como um mecanismo de modelo. Dê uma olhada neste fragmento HTML salvo como template.htm
:-.
< p > Hello, < ?php echo $name; ? > ! </ p >
Se tags curtas estiverem ativadas no seu servidor, isso também deve funcionar:-
< p > Hello, < ?= $name ? > </ p >
Para exibir este modelo, você pode ter código PHP que se parece com isso (armazenado em um arquivo separado do modelo):-
$ f3 = require ( ' lib/base.php ' );
$ f3 -> route ( ' GET / ' ,
function ( $ f3 ) {
$ f3 -> set ( ' name ' , ' world ' );
$ view = new View ;
echo $ view -> render ( ' template.htm ' );
// Previous two lines can be shortened to : -
// echo View :: instance () - > render ( 'template.htm' );
}
);
$ f3 -> run ();
O único problema do uso do PHP como um mecanismo de modelo, devido ao código PHP incorporado nesses arquivos, é o esforço consciente necessário para seguir as diretrizes sobre a separação de preocupações e resistir à tentação da mixagem da lógica de negócios com sua interface do usuário.
Como alternativa ao PHP, você pode usar o próprio mecanismo de modelo da F3. O fragmento HTML acima pode ser reescrito como:-
< p > Hello, {{ @name }}! </ p >
e o código necessário para visualizar este modelo:-
$ f3 = require ( ' lib/base.php ' );
$ f3 -> route ( ' GET / ' ,
function ( $ f3 ) {
$ f3 -> set ( ' name ' , ' world ' );
$ template = new Template ;
echo $ template -> render ( ' template.htm ' );
// Above lines can be written as : -
// echo Template :: instance () - > render ( 'template.htm' );
}
);
$ f3 -> run ();
Como os tokens de roteamento usados para capturar variáveis nos URLs (ainda lembre -se do exemplo GET /brew/@count
na seção anterior?), Os tokens de modelo F3 começam com o símbolo @
seguido de uma série de letras e dígitos fechados em aparelhos encaracolados. O primeiro personagem deve ser alfa. Os tokens de modelo têm uma correspondência individual com variáveis de estrutura. A estrutura substitui automaticamente um token pelo valor armazenado em uma variável de mesmo nome.
Em nosso exemplo, o F3 substitui o token @name
em nosso modelo pelo valor que atribuímos à variável de nome. Em tempo de execução, a saída do código acima será:-
< p > Hello, world </ p >
Preocupado com o desempenho dos modelos F3? Em tempo de execução, a estrutura analisa e compila/converte um modelo F3 em código PHP na primeira vez que ele é exibido via $template->render()
. A estrutura usa esse código compilado em todas as chamadas subsequentes. Portanto, o desempenho deve ser o mesmo que os modelos PHP, se não for melhor devido à otimização do código feita pelo compilador de modelo quando modelos mais complexos estão envolvidos.
Se você usa o mecanismo de modelo do PHP ou o próprio F3, a renderização do modelo pode ser significativamente mais rápida se você tiver APC, Wincache ou XCache disponível no seu servidor.
Como mencionado anteriormente, as variáveis da estrutura podem conter qualquer tipo de dados PHP. No entanto, o uso de tipos de dados não escalares nos modelos F3 pode produzir resultados estranhos se você não tomar cuidado. Expressões em aparelhos encaracolados sempre serão avaliados e convertidos em string. Você deve limitar suas variáveis de interface do usuário a escalares simples:- string
, integer
, boolean
ou Tipos de dados float
.
Mas e as matrizes? A Fat Livre reconhece matrizes e você pode empregá-las em seus modelos. Você pode ter algo como:-
< p > {{ @buddy[0] }}, {{ @buddy[1] }}, and {{ @buddy[2] }} </ p >
E preencha a matriz @buddy
em seu código PHP antes de servir o modelo:-
$ f3 -> set ( ' buddy ' ,[ ' Tom ' , ' Dick ' , ' Harry ' ]);
No entanto, se você simplesmente inserir {{ @buddy }}
em seu modelo, o PHP o substituirá por 'Array'
porque converte o token em uma string. O PHP, por outro lado, gerará uma Array to string conversion
em tempo de execução.
F3 permite incorporar expressões em modelos. Essas expressões podem assumir várias formas, como cálculos aritméticos, expressões booleanas, constantes de PHP, etc. Aqui estão alguns exemplos:-
{{ 2*(@page-1) }}
{{ (int)765.29+1.2e3 }}
< option value =" F " {{ @active? 'selected=" selected "':'' }} > Female </ option >
{{ var_dump(@xyz) }}
< p > That is {{ preg_match('/Yes/i',@response)?'correct':'wrong' }}! </ p >
{{ @obj- > property }}
Uma nota adicional sobre expressões de matriz: observe que @foo.@bar
é uma string concatenation $foo.$bar
), enquanto @foo.bar
se traduz em $foo['bar']
. Se $foo[$bar]
é o que você pretendia, use a notação regular @foo[@bar]
.
Variáveis de estrutura também podem conter funções anônimas:
$ f3 -> set ( ' func ' ,
function ( $ a , $ b ) {
return $ a . ' , ' . $ b ;
}
);
O mecanismo de modelo F3 interpretará o token como esperado, se você especificar a seguinte expressão:
{{ @func('hello','world') }}
Substituição variável simples é uma coisa que todos os motores de modelo têm. Sem gordura tem mais as mangas:-
< include href =" header.htm " />
A diretiva incorporará o conteúdo do modelo de cabeçalho.htm na posição exata em que a diretiva é declarada. Você também pode ter conteúdo dinâmico na forma de:-
< include href =" {{ @content }} " />
Um uso prático para essa diretiva de modelo é quando você tem várias páginas com um layout HTML comum, mas com conteúdo diferente. Instruir a estrutura para inserir um sub-tempo em seu modelo principal é tão simples quanto escrever o seguinte código PHP:-
// switch content to your blog sub - template
$ f3 -> set ( ' content ' , ' blog.htm ' );
// in another route , switch content to the wiki sub - template
$ f3 -> set ( ' content ' , ' wiki.htm ' );
Um subdemado pode, por sua vez, conter qualquer número de diretivas. F3 permite modelos aninhados ilimitados.
Você pode especificar nomes de arquivos com algo diferente de extensões de arquivos .htm ou .html, mas é mais fácil visualizá -los no seu navegador da web durante a fase de desenvolvimento e depuração. O mecanismo de modelo não se limita à renderização de arquivos HTML. Na verdade, você pode usar o mecanismo de modelo para renderizar outros tipos de arquivos.
A diretiva <include>
também possui um atributo opcional if
você pode especificar uma condição que precisa ser satisfeita antes que o sub-templado seja inserido:-
< include if =" {{ count(@items) }} " href =" items.htm " />
Durante o curso da redação/depuração de programas movidos a F3 e modelos de design, pode haver casos em que desative a exibição de um bloco de HTML pode ser útil. Você pode usar a diretiva <exclude>
para esse fim:-
< exclude >
< p > A chunk of HTML we don't want displayed at the moment </ p >
</ exclude >
É como a tag de comentário <!-- comment -->
HTML, mas a diretiva <exclude>
torna o bloco HTML totalmente invisível quando o modelo for renderizado.
Aqui está outra maneira de excluir o conteúdo do modelo ou adicionar comentários:-
{* < p > A chunk of HTML we don't want displayed at the moment </ p > *}
Outro recurso de modelo útil é a diretiva <check>
. Ele permite incorporar um fragmento HTML, dependendo da avaliação de uma certa condição. Aqui estão alguns exemplos:-
< check if =" {{ @page=='Home' }} " >
< false > < span > Inserted if condition is false </ span > </ false >
</ check >
< check if =" {{ @gender=='M' }} " >
< true >
< div > Appears when condition is true </ div >
</ true >
< false >
< div > Appears when condition is false </ div >
</ false >
</ check >
Você pode ter tantas diretivas <check>
aninhadas quanto necessário.
Uma expressão de F3 dentro de um atributo IF que equivale a NULL
, uma corda vazia, um FALSE
booleano, uma matriz vazia ou zero, invoca automaticamente <false>
. Se o seu modelo não tiver um bloco <false>
, as tags de abertura e fechamento <true>
são opcionais:-
< check if =" {{ @loggedin }} " >
< p > HTML chunk to be included if condition is true </ p >
</ check >
A gordura também pode lidar com blocos html repetitivos:-
< repeat group =" {{ @fruits }} " value =" {{ @fruit }} " >
< p > {{ trim(@fruit) }} </ p >
</ repeat >
O atributo group
@fruits
dentro da diretiva <repeat>
deve ser uma matriz e deve ser definido no seu código PHP de acordo:-
$ f3 -> set ( ' fruits ' ,[ ' apple ' , ' orange ' , ' banana ' ]);
Nada é obtido atribuindo um valor a @fruit
no seu código de aplicativo. A FAT Livre ignora qualquer valor predefinido que possa ter, porque usa a variável para representar o item atual durante a iteração sobre o grupo. A saída do fragmento de modelo HTML acima e o código PHP correspondente se torna:-
< p > apple </ p >
< p > orange </ p >
< p > banana </ p >
A estrutura permite um ninho ilimitado de blocos <repeat>
:-
< repeat group =" {{ @div }} " key =" {{ @ikey }} " value =" {{ @idiv }} " >
< div >
< p > < span > < b > {{ @ikey }} </ b > </ span > </ p >
< p >
< repeat group =" {{ @idiv }} " value =" {{ @ispan }} " >
< span > {{ @ispan }} </ span >
</ repeat >
</ p >
</ div >
</ repeat >
Aplique o seguinte comando f3:-
$ f3 -> set ( ' div ' ,
[
' coffee ' =>[ ' arabica ' , ' barako ' , ' liberica ' , ' kopiluwak ' ],
' tea ' =>[ ' darjeeling ' , ' pekoe ' , ' samovar ' ]
]
);
Como resultado, você recebe o seguinte fragmento HTML:-
< div >
< p > < span > < b > coffee </ b > </ span > </ p >
< p >
< span > arabica </ span >
< span > barako </ span >
< span > liberica </ span >
< span > kopiluwak </ span >
< p >
</ div >
< div >
< p > < span > < b > tea </ b > </ span > </ p >
< p >
< span > darjeeling </ span >
< span > pekoe </ span >
< span > samovar </ span >
</ p >
</ div >
Incrível, não é? E a única coisa que você teve que fazer no PHP era definir o conteúdo de uma única div
F3 para substituir o token @div
. A FAT-L-Free facilita muito a programação e o design de modelos da Web.
O atributo value
da diretiva de modelos <repeat>
retorna o valor do elemento atual na iteração. Se você precisar obter a tecla Array do elemento atual, use o atributo key
. O atributo key
é opcional.
<repeat>
também possui um atributo de contador opcional que pode ser usado da seguinte forma:-
< repeat group =" {{ @fruits }} " value =" {{ @fruit }} " counter =" {{ @ctr }} " >
< p class =" {{ @ctr%2?'odd':'even' }} " > {{ trim(@fruit) }} </ p >
</ repeat >
Internamente, o modelo de modelo da F3 registra o número de iterações de loop e salva esse valor na variável/token @ctr
, que é usada em nosso exemplo para determinar a classificação ímpar/uniforme.
Se você precisar inserir tokens F3 dentro de uma seção <script>
ou <style>
do seu modelo, a estrutura ainda os substituirá da maneira usual:-
< script type =" text/javascript " >
function notify ( ) {
alert ( 'You are logged in as: {{ @userID }}' ) ;
}
</ script >
Incorporar as diretivas de modelos dentro de suas tags <script>
ou <style>
não requer manuseio especial:-
< script type =" text/javascript " >
var discounts = [ ] ;
< repeat group = "{{ @rates }}" value = "{{ @rate }}" >
// whatever you want to repeat in Javascript, e.g.
discounts.push(" { { @ rate } } ");
</ repeat >
</ script >
Por padrão, o FAT Free usa o conjunto de caracteres UTF-8, a menos que seja alterado. Você pode substituir esse comportamento emitindo algo como:-
$ f3 -> set ( ' ENCODING ' , ' ISO-8859-1 ' );
Depois de informar a estrutura do conjunto de caracteres desejado, o F3 o usará em todos os modelos HTML e XML até se alterar novamente.
Como mencionado anteriormente nesta seção, a estrutura não se limita aos modelos HTML. Você pode processar modelos XML da mesma forma. A mecânica é praticamente semelhante. Você ainda tem os mesmos {{ @variable }}
e {{ expression }}
tokens, <repeat>
, <check>
, <include>
e <exclude>
diretivos à sua disposição. Basta dizer a F3 que você está passando um arquivo XML em vez de HTML:-
echo Template:: instance ()-> render ( ' template.xml ' , ' application/xml ' );
O segundo argumento representa o tipo MIME do documento que está sendo renderizado.
O componente de visualização do MVC cobre tudo o que não se enquadra no modelo e no controlador, o que significa que sua apresentação pode e deve incluir todos os tipos de interfaces de usuário, como RSS, e-mail, RDF, FOAF, arquivos de texto etc. O exemplo Abaixo mostra como separar sua apresentação por e-mail da lógica de negócios do seu aplicativo:-
MIME-Version: 1.0
Content-type: text/html; charset={{ @ENCODING }}
From: {{ @from }}
To: {{ @to }}
Subject: {{ @subject }}
< p > Welcome, and thanks for joining {{ @site }}! </ p >
Salve o modelo de e-mail acima como Welcome.txt. O código F3 associado seria:-
$ f3 -> set ( ' from ' , ' <[email protected]> ' );
$ f3 -> set ( ' to ' , ' <[email protected]> ' );
$ f3 -> set ( ' subject ' , ' Welcome ' );
ini_set ( ' sendmail_from ' , $ f3 -> get ( ' from ' ));
mail (
$ f3 -> get ( ' to ' ),
$ f3 -> get ( ' subject ' ),
Template:: instance ()-> render ( ' email.txt ' , ' text/html ' )
);
Dica: Substitua a função SMTP Mail () com IMAP_MAIL () se o seu script se comunicar com um servidor IMAP.
Agora não é algo? Obviamente, se você tiver um pacote de destinatários de e-mail, estaria usando um banco de dados para preencher os tokens do primeiro nome, lenço e e-mail.
Aqui está uma solução alternativa usando o plug-in SMTP do F3:-
$ mail = new SMTP ( ' smtp.gmail.com ' , 465 , ' SSL ' , ' [email protected] ' , ' secret ' );
$ mail -> set ( ' from ' , ' <[email protected]> ' );
$ mail -> set ( ' to ' , ' "Slasher" <[email protected]> ' );
$ mail -> set ( ' subject ' , ' Welcome ' );
$ mail -> send (Template:: instance ()-> render ( ' email.txt ' ));
F3 suporta vários idiomas imediatamente.
Primeiro, crie um arquivo de dicionário com a seguinte estrutura (um arquivo por idioma):-
<?php
return [
' love ' => ' I love F3 ' ,
' today ' => ' Today is {0,date} ' ,
' pi ' => ' {0,number} ' ,
' money ' => ' Amount remaining: {0,number,currency} '
];
Salve -o como dict/en.php
. Vamos criar outro dicionário, desta vez para o alemão. Salve o arquivo como dict/de.php
:-
<?php
return [
' love ' => ' Ich liebe F3 ' ,
' today ' => ' Heute ist {0,date} ' ,
' money ' => ' Restbetrag: {0,number,currency} '
];
Os dicionários nada mais são do que pares de valor-chave. A F3 instancia automaticamente variáveis de estrutura com base nas chaves nos arquivos de idioma. Como tal, é fácil incorporar essas variáveis como tokens em seus modelos. Usando o mecanismo de modelo F3:-
< h1 > {{ @love }} </ h1 >
< p >
{{ @today,time() | format }}. < br />
{{ @money,365.25 | format }} < br />
{{ @pi }}
</ p >
E a versão mais longa que utiliza o PHP como um mecanismo de modelo:-
<?php $ f3 =Base:: instance (); ?>
<h1> <?php echo $ f3 -> get ( ' love ' ); ?> </h1>
<p>
<?php echo $ f3 -> get ( ' today ' , time ()); ?> .<br />
<?php echo $ f3 -> get ( ' money ' , 365.25 ); ?>
<?php echo $ f3 -> get ( ' pi ' ); ?>
</p>
Em seguida, instruímos F3 a procurar dicionários na dict/
pasta:-
$ f3 -> set ( ' LOCALES ' , ' dict/ ' );
Mas como a estrutura determina qual idioma usar? A F3 detectará automaticamente, observando os cabeçalhos de solicitação HTTP primeiro, especificamente o cabeçalho Accept-Language
enviada pelo navegador.
Para substituir esse comportamento, você pode acionar F3 para usar um idioma especificado pelo usuário ou aplicativo:-
$ f3 -> set ( ' LANGUAGE ' , ' de ' );
Nota: No exemplo acima, o Pi -chave existe apenas no dicionário inglês. A estrutura sempre usará o inglês ( en
) como um substituto para preencher as teclas que não estão presentes no idioma especificado (ou detectado).
Você também pode criar arquivos de dicionário para variantes de idiomas como en-US
, es-AR
, etc. Nesse caso, F3 usará a variante de idioma primeiro (como es-AR
). Se houver chaves que não existirem na variante, a estrutura procurará a chave no (s) idioma (s) raiz es
), use o arquivo de idioma en
como o fallback final. Os pares de valor-chave do dicionário tornam-se variáveis F3, uma vez referenciadas. Verifique se as chaves não entram em conflito com nenhuma variável de estrutura instanciada via $f3->set()
, $f3->mset()
ou $f3->config()
.
Você notou o padrão peculiar 'Today is {0,date}'
em nosso exemplo anterior? A capacidade multilíngue da F3 depende das regras de formatação de string/mensagem do projeto da UTI. A estrutura usa seu próprio subconjunto da implementação da formatação da String da UTI. Não há necessidade de a extensão intl
do PHP ser ativada no servidor.
Mais uma coisa: F3 também pode carregar arquivos formatados no estilo .ini como dicionários:-
love = " I love F3 "
today = " Today is {0,date} "
pi = " {0,number} "
money = " Amount remaining: {0,number,currency} "
Salve como dict/en.ini
para que a estrutura possa carregá -lo automaticamente.
Por padrão, o manipulador de exibição e o modelo escapa de todas as variáveis renderizadas, ou seja, convertidas em entidades HTML para protegê -lo de possíveis XSS e ataques de injeção de código. Por outro lado, se você deseja passar fragmentos HTML válidos do código do seu aplicativo para o seu modelo:-
$ f3 -> set ( ' ESCAPE ' , FALSE );
Isso pode ter efeitos indesejáveis. Você pode não querer que todas as variáveis passem por desconto. A gordura permite que você une descendente de variáveis individualmente. Para modelos F3:-
{{ @html_content | raw }}
No caso de modelos de php:-
<?php echo View:: instance ()-> raw ( $ html_content ); ?>
Como adição à escapação automática de variáveis F3, a estrutura também oferece uma mão livre para higienizar a entrada do usuário de formulários HTML:-
$ f3 -> scrub ( $ _GET , ' p; br; span; div; a ' );
Este comando desviará todas as tags (exceto as especificadas no segundo argumento) e caracteres inseguros da variável especificada. Se a variável contiver uma matriz, cada elemento na matriz será higienizado recursivamente. Se um asterisco (*) for passado como o segundo argumento, $f3->scrub()
permite que todas as tags HTML passem por meio de intocadas e simplesmente remover caracteres de controle inseguros.
A FAT é projetada para facilitar a interface com os bancos de dados SQL. Se você não é do tipo para mergulhar em detalhes sobre o SQL, mas se incline mais para o manuseio de dados orientado a objetos, poderá ir diretamente para a próxima seção deste tutorial. No entanto, se você precisar executar algumas tarefas complexas de manuseio de dados e otimização de desempenho do banco de dados, o SQL é o caminho a percorrer.
Estabelecendo comunicação com um mecanismo SQL como MySQL, SQLite, SQL Server, Sybase e Oracle é feito usando o comando familiar $f3->set()
. Conectar-se a um banco de dados SQLite seria:-
$ db = new DB SQL ( ' sqlite:/absolute/path/to/your/database.sqlite ' );
Outro exemplo, desta vez com o MySQL:-
$ db = new DB SQL (
' mysql:host=localhost;port=3306;dbname=mysqldb ' ,
' admin ' ,
' p455w0rD '
);
OK. Foi fácil, não foi? É assim que você faria a mesma coisa no PHP comum. Você só precisa conhecer o formato DSN do banco de dados que está se conectando. Veja a seção PDO do manual PHP.
Vamos continuar nosso código PHP:-
$ f3 -> set ( ' result ' , $ db -> exec ( ' SELECT brandName FROM wherever ' ));
echo Template:: instance ()-> render ( ' abc.htm ' );
Huh, o que está acontecendo aqui? Não devemos configurar coisas como PDoS, declarações, cursores etc.? A resposta simples é: você não precisa. F3 simplifica tudo, cuidando de todo o trabalho duro no back -end.
Desta vez, criamos um modelo HTML como abc.htm
que tem no mínimo o seguinte:-
< repeat group =" {{ @result }} " value =" {{ @item }} " >
< span > {{ @item.brandName }} </ span >
</ repeat >
Na maioria dos casos, o conjunto de comandos SQL deve ser suficiente para gerar um resultado pronto para a Web, para que você possa usar a variável de matriz result
diretamente em seu modelo. Seja como for, sem gordura não o impedirá de entrar em seus internos do SQL Handler. De fato, a classe DBSQL
da F3 deriva diretamente da classe PDO
do PHP, para que você ainda tenha acesso aos componentes e primitivos de PDO subjacentes envolvidos em cada processo, se precisar de algum controle de grãos finos.
Aqui está outro exemplo. Em vez de uma única declaração fornecida como um argumento para o comando $db->exec()
, você também pode passar uma matriz de instruções SQL:-
$ db -> exec (
[
' DELETE FROM diet WHERE food="cola" ' ,
' INSERT INTO diet (food) VALUES ("carrot") ' ,
' SELECT * FROM diet '
]
);
O F3 é inteligente o suficiente para saber que, se você estiver passando uma variedade de instruções SQL, isso indica uma transação em lote SQL. Você não precisa se preocupar com reversão e comprometimento do SQL, porque a estrutura reverterá automaticamente para o estado inicial do banco de dados se ocorrer algum erro durante a transação. Se for bem -sucedido, o F3 comete todas as alterações feitas no banco de dados.
Você também pode iniciar e terminar uma transação programaticamente:-
$ db -> begin ();
$ db -> exec ( ' DELETE FROM diet WHERE food="cola" ' );
$ db -> exec ( ' INSERT INTO diet (food) VALUES ("carrot") ' );
$ db -> exec ( ' SELECT * FROM diet ' );
$ db -> commit ();
Uma reversão ocorrerá se alguma das declarações encontrar um erro.
Para obter uma lista de todas as instruções do banco de dados emitidas:-
echo $ db -> log ();
Passando argumentos de string para declarações SQL está repleto de perigo. Considere o seguinte:-
$ db -> exec (
' SELECT * FROM users ' .
' WHERE username=" ' . $ f3 -> get ( ' POST.userID ' . ' " ' )
);
Se a variável POST
userID
não passar por nenhum processo de saneamento de dados, um usuário malicioso poderá passar a seguinte string e danificar seu banco de dados irreversivelmente:-
admin " ; DELETE FROM users; SELECT " 1
Felizmente, consultas parametrizadas ajudam você a mitigar esses riscos:-
$ db -> exec (
' SELECT * FROM users WHERE userID=? ' ,
$ f3 -> get ( ' POST.userID ' )
);
Se a F3 detectar que o valor do parâmetro/token da consulta é uma string, a camada de acesso de dados subjacente escapa da string e adiciona cotações conforme necessário.
Nosso exemplo na seção anterior será muito mais seguro da injeção de SQL se escrita desta maneira:-
$ db -> exec (
[
' DELETE FROM diet WHERE food=:name ' ,
' INSERT INTO diet (food) VALUES (?) ' ,
' SELECT * FROM diet '
],
[
array ( ' :name ' => ' cola ' ),
array ( 1 => ' carrot ' ),
NULL
]
);
F3 é embalado com mapeadores de objetos fáceis de usar (ORMs) que ficam entre o seu aplicativo e seus dados-tornando-o muito mais fácil e rápido para você escrever programas que lidam com operações de dados comuns-como criar, recuperar, atualizar, atualizar, e excluir informações (CRUD) dos bancos de dados SQL e NOSQL. Os mapeadores de dados fazem a maior parte do trabalho mapeando as interações do objeto PHP para as consultas de back -end correspondentes.
Suponha que você tenha um banco de dados MySQL existente contendo uma tabela de usuários do seu aplicativo. (Sqlite, PostgreSQL, SQL Server, Sybase também.) Ele teria sido criado usando o seguinte comando SQL:-
CREATE TABLE users (
userID VARCHAR ( 30 ),
password VARCHAR ( 30 ),
visits INT ,
PRIMARY KEY (userID)
);
NOTA: O MongoDB é um mecanismo de banco de dados NoSQL e inerentemente sem esquema. A F3 possui sua própria implementação rápida e leve NoSQL chamada Jig, que usa arquivos planos codificados por PHP-serrializados ou codificados por JSON. Essas camadas de abstração não requerem estruturas de dados rígidas. Os campos podem variar de um registro para outro. Eles também podem ser definidos ou descartados em tempo real.
Agora de volta ao SQL. Primeiro, estabelecemos comunicação com nosso banco de dados.
$ db = new DB SQL (
' mysql:host=localhost;port=3306;dbname=mysqldb ' ,
' admin ' ,
' wh4t3v3r '
);
Para recuperar um registro da nossa tabela:-
$ user = new DB SQL Mapper ( $ db , ' users ' );
$ user -> load ([ ' userID=? ' , ' tarzan ' ]);
A primeira linha instancia um objeto de mapeador de dados que interage com a tabela users
em nosso banco de dados. Atrás da cena, o F3 recupera a estrutura da tabela users
e determina quais campo (s) são definidos como chaves primárias. Nesse ponto, o objeto Mapper ainda não contém dados (estado seco), portanto, $user
é nada mais do que um objeto estruturado - mas contém os métodos necessários para executar as operações básicas do CRUD e alguns extras. Para recuperar um registro de nossa tabela de usuários com um campo userID
contendo o valor da string tarzan
, usamos o load() method
. Esse processo é chamado de "hidratação automática" do objeto de mapeador de dados.
Fácil, não foi? F3 entende que uma tabela SQL já possui uma definição estrutural existente no próprio mecanismo de banco de dados. Ao contrário de outras estruturas, a F3 não requer declarações de classe extra (a menos que você queira estender os mapeadores de dados para se ajustarem a objetos complexos), nenhum Matriz Php redundante/objeto de propriedade para mapeamentos (duplicação de esforços), sem geradores de código (que exigem código Regeneração Se a estrutura do banco de dados mudar), nenhum arquivo XML/YAML estúpido para configurar seus modelos, sem comandos supérfluos apenas para recuperar um único registro. Com F3, um simples redimensionamento de um campo varchar
no MySQL não exige uma alteração no seu código de aplicativo. Consistente com o MVC e "Separação de preocupações", o administrador do banco de dados tem tanto controle sobre os dados (e as estruturas) quanto um designer de modelo tem sobre os modelos HTML/XML.
Se você preferir trabalhar com bancos de dados NoSQL, as semelhanças na sintaxe de consulta são superficiais. No caso do MongoDB Data Mapper, o código equivalente seria:-
$ db = new DB Mongo ( ' mongodb://localhost:27017 ' , ' testdb ' );
$ user = new DB Mongo Mapper ( $ db , ' users ' );
$ user -> load ([ ' userID ' => ' tarzan ' ]);
Com o gabarito, a sintaxe é semelhante ao modelo de modelo do F3:-
$ db = new DB Jig ( ' db/data/ ' , DB Jig:: FORMAT_JSON );
$ user = new DB Jig Mapper ( $ db , ' users ' );
$ user -> load ([ ' @userID=? ' , ' tarzan ' ]);
A estrutura mapeia automaticamente as visits
de campo em nossa tabela para uma propriedade de mapeador de dados durante a instanciação do objeto, ou seja, $user=new DBSQLMapper($db,'users');
. Depois que o objeto for criado, $user->password
e $user->userID
mapeiam para os campos password
e userID
em nossa tabela, respectivamente.
Você não pode adicionar ou excluir um campo mapeado ou alterar a estrutura de uma tabela usando o ORM. Você deve fazer isso no MySQL, ou em qualquer mecanismo de banco de dados que você esteja usando. Depois de fazer as alterações no seu mecanismo de banco de dados, o FAT Livre sincronizará automaticamente a nova estrutura de tabela com seu objeto de mapeador de dados quando você executar seu aplicativo.
F3 deriva a estrutura do mapeador de dados diretamente do esquema do banco de dados. Não adivinhação envolvida. Ele entende as diferenças entre os mecanismos MySQL, SQLite, MSSQL, Sybase e PostgreSQL.
Os identificadores SQL não devem usar palavras reservadas e devem ser limitadas aos caracteres alfanuméricos AZ
, 0-9
e ao símbolo sublinhado ( _
). Nomes de colunas contendo espaços (ou caracteres especiais) e cercados por citações na definição de dados não são compatíveis com o ORM. Eles não podem ser representados adequadamente como propriedades do objeto PHP.
Digamos que queremos incrementar o número de visitas do usuário e atualizar o registro correspondente em nossa tabela de usuários, podemos adicionar o seguinte código:-
$ user -> visits ++;
$ user -> save ();
Se quiséssemos inserir um registro, seguimos este processo:-
$ user = new DB SQL Mapper ( $ db , ' users ' );
// or $ user = new DB Mongo Mapper ($ db , 'users' );
// or $ user = new DB Jig Mapper ($ db , 'users' );
$ user -> userID = ' jane ' ;
$ user -> password = password_hash ( ' secret ' , PASSWORD_BCRYPT , [ ' cost ' => 12 ]);
$ user -> visits = 0 ;
$ user -> save ();
Ainda usamos o mesmo método save()
. Mas como o F3 sabe quando um registro deve ser inserido ou atualizado? Na época em que um objeto de mapeador de dados é hidratado automático por uma recuperação de registro, a estrutura acompanha as chaves primárias do registro (ou _id
, no caso de MongoDB e Jig) - para que saiba qual registro deve ser atualizado ou excluído - mesmo Quando os valores das teclas primários são alterados. Um mapeador de dados programaticamente hidratado - cujos valores não foram recuperados do banco de dados, mas preenchidos pelo aplicativo - não terão memória dos valores anteriores em suas chaves primárias. O mesmo se aplica a MongoDB e Jig, mas usando o objeto _id
como referência. Portanto, quando instanciamos o objeto $user
acima e preencemos suas propriedades com valores do nosso programa - sem recuperar um registro da tabela de usuários, a F3 sabe que ele deve inserir esse registro.
Um objeto de mapeador não estará vazio após um save()
. Se você deseja adicionar um novo registro ao seu banco de dados, deve primeiro desidratar o mapeador:-
$ user -> reset ();
$ user -> userID = ' cheetah ' ;
$ user -> password = password_hash ( ' unknown ' , PASSWORD_BCRYPT , [ ' cost ' => 12 ]);
$ user -> save ();
Chamando save()
uma segunda vez sem invocar reset()
simplesmente atualizará o registro atualmente apontado pelo mapeador.
Embora a questão de ter teclas primárias em todas as tabelas no seu banco de dados seja argumentativa, a F3 não impede que você crie um objeto de mapeador de dados que se comunique com uma tabela que não contém chaves primárias. A única desvantagem é: você não pode excluir ou atualizar um registro mapeado, porque não há absolutamente nenhuma maneira de F3 determinar qual registro está se referindo mais o fato de que as referências posicionais não são confiáveis. Os IDs da linha não são portáteis em diferentes mecanismos SQL e não podem ser retornados pelo driver de banco de dados PHP.
Para remover um registro mapeado da nossa tabela, invocar o método erase()
em um mapeador de dados hidratado automaticamente. Por exemplo:-
$ user = new DB SQL Mapper ( $ db , ' users ' );
$ user -> load ([ ' userID=? AND password=? ' , ' cheetah ' , ' ch1mp ' ]);
$ user -> erase ();
A sintaxe de consulta de Jig seria um pouco semelhante:-
$ user = new DB Jig Mapper ( $ db , ' users ' );
$ user -> load ([ ' @userID=? AND @password=? ' , ' cheetah ' , ' chimp ' ]);
$ user -> erase ();
E o equivalente do MongoDB seria:-
$ user = new DB Mongo Mapper ( $ db , ' users ' );
$ user -> load ([ ' userID ' => ' cheetah ' , ' password ' => ' chimp ' ]);
$ user -> erase ();
Para descobrir se nosso mapeador de dados foi hidratado ou não:-
if ( $ user -> dry ())
echo ' No record matching criteria ' ;
Cobrimos os manipuladores CRUD. Existem alguns métodos extras que você pode achar úteis:-
$ f3 -> set ( ' user ' , new DB SQL Mapper ( $ db , ' users ' ));
$ f3 -> get ( ' user ' )-> copyFrom ( ' POST ' );
$ f3 -> get ( ' user ' )-> save ();
Observe que também podemos usar variáveis sem gordura como contêineres para objetos de mapeador. O método copyFrom()
hidrata o objeto Mapper com elementos de uma variável de matriz de estrutura, cujas teclas de matriz devem ter nomes idênticos às propriedades do objeto Mapper, que por sua vez correspondem aos nomes de campo do registro. Portanto, quando um formulário da Web é enviado (assumindo que o atributo de nome HTML seja definido como userID
), o conteúdo desse campo de entrada é transferido para $_POST['userID']
, duplicado por F3 em sua variável POST.userID
e salva para o campo mapeado $user->userID
no banco de dados. O processo se torna muito simples se todos eles tiverem elementos nomeados idênticos. Consistência nas teclas de matriz, ou seja, nomes de token de modelo, nomes de variáveis de estrutura e nomes de campo é chave :)
Por outro lado, se quiséssemos recuperar um registro e copiar os valores do campo para uma variável de estrutura para uso posterior, como renderização de modelo:-
$ f3 -> set ( ' user ' , new DB SQL Mapper ( $ db , ' users ' ));
$ f3 -> get ( ' user ' )-> load ([ ' userID=? ' , ' jane ' ]);
$ f3 -> get ( ' user ' )-> copyTo ( ' POST ' );
Podemos então atribuir {{ @post.userId}} ao mesmo atributo de valor do campo de entrada. Para resumir, o campo de entrada HTML ficará assim:-
< input type =" text " name =" userID " value =" {{ @POST.userID }} " />
Os métodos save()
, update()
, copyFrom()
e as variantes parametrizadas de load()
e erase()
estão a salvo da injeção de SQL.
Por padrão, um método load()
de mapeador de dados recupera apenas o primeiro registro que corresponde aos critérios especificados. Se você tiver mais de um que atenda à mesma condição que o primeiro registro carregado, pode usar o método skip()
para navegação:-
$ user = new DB SQL Mapper ( $ db , ' users ' );
$ user -> load ( ' visits>3 ' );
// Rewritten as a parameterized query
$ user -> load ([ ' visits>? ' , 3 ]);
// For MongoDB users : -
// $ user = new DB Mongo Mapper ($ db , 'users' );
// $ user - > load ([ 'visits' = > [ '$gt' = > 3 ]]);
// If you prefer Jig : -
// $ user = new DB Jig Mapper ($ db , 'users' );
// $ user - > load ( '@visits>?' , 3 );
// Display the userID of the first record that matches the criteria
echo $ user -> userID ;
// Go to the next record that matches the same criteria
$ user -> skip (); // Same as $ user - > skip ( 1 );
// Back to the first record
$ user -> skip (- 1 );
// Move three records forward
$ user -> skip ( 3 );
Você pode usar $user->next()
como substituto para $user->skip()
e $user->prev()
se você acha que isso dá mais significado para $user->skip(-1)
.
Use o método dry()
para verificar se você manobrou além dos limites do conjunto de resultados. dry()
retornará verdadeiro se você tentar skip(-1)
no primeiro registro. Ele também retornará verdadeiro se você skip(1)
no último registro que atende aos critérios de recuperação.
O método load()
aceita um segundo argumento: uma variedade de opções contendo pares de valor-chave, como:-
$ user -> load (
[ ' visits>? ' , 3 ],
[
' order ' => ' userID DESC '
'offset'=> 5 ,
' limit ' => 3
]
);
Se você está usando o MySQL, a consulta se traduz em:-
SELECT * FROM users
WHERE visits > 3
ORDER BY userID DESC
LIMIT 3 OFFSET 5 ;
Esta é uma maneira de apresentar dados em pequenos pedaços. Aqui está outra maneira de pagar resultados:-
$ page = $ user -> paginate ( 2 , 5 ,[ ' visits>? ' , 3 ]);
No cenário acima, a F3 recuperará registros que correspondem às 'visits>3'
. Em seguida, limitará os resultados a 5 registros (por página), começando na página Offset 2 (baseado em 0). A estrutura retornará uma matriz que consiste nos seguintes elementos:-
[subset] array of mapper objects that match the criteria
[count] number of subsets available
[pos] actual subset position
A posição real do subconjunto retornada será nula se o primeiro argumento de paginate()
for um número negativo ou exceder o número de subconjuntos encontrados.
Há casos em que você precisa recuperar um valor calculado de um campo ou um valor de referência cruzada de outra tabela. Digite campos virtuais. O Mini-Aorm SQL permite que você trabalhe em dados derivados dos campos existentes.
Suponha que tenhamos a tabela a seguir definida como:-
CREATE TABLE products
productID VARCHAR ( 30 ),
description VARCHAR ( 255 ),
supplierID VARCHAR ( 30 ),
unitprice DECIMAL ( 10 , 2 ),
quantity INT ,
PRIMARY KEY (productID)
);
Não existe um campo totalprice
, para que possamos dizer à estrutura para solicitar do mecanismo de banco de dados o produto aritmético dos dois campos:-
$ item = new DB SQL Mapper ( $ db , ' products ' );
$ item -> totalprice = ' unitprice*quantity ' ;
$ item -> load ([ ' productID=:pid ' , ' :pid ' => ' apple ' ]);
echo $ item -> totalprice ;
O snippet de código acima define um campo virtual chamado totalprice
, calculado multiplicando unitprice
pela quantity
. O SQL Mapper salva essa regra/fórmula; portanto, quando chegar a hora de recuperar o registro do banco de dados, podemos usar o campo virtual como um campo mapeado regular.
Você pode ter campos virtuais mais complexos:-
$ item -> mostNumber = ' MAX(quantity) ' ;
$ item -> load ();
echo $ item -> mostNumber ;
Desta vez, a estrutura recupera o produto com a quantidade mais alta (notifique o método load()
não define nenhum critério; portanto, todos os registros da tabela serão processados). Obviamente, o campo virtual mostNumber
ainda fornecerá a figura certa se você desejar limitar a expressão a um grupo específico de registros que correspondem a um critério especificado.
Você também pode derivar um valor de outra tabela:-
$ item -> supplierName =
' SELECT name FROM suppliers ' .
' WHERE products.supplierID=suppliers.supplierID ' ;
$ item -> load ();
echo $ item -> supplierName ;
Toda vez que você carrega um registro da tabela de produtos, o ORM referências cruzadas na tabela de produtos na tabela products
com supplierID
supplerID
tabela suppliers
.
Para destruir um campo virtual, use unset($item->totalPrice);
. A expressão isset($item->totalPrice)
retorna true se o campo virtual totalPrice
foi definido ou false se o contrário.
Lembre -se de que um campo virtual deve ser definido antes da recuperação de dados. O ORM não executa o cálculo real, nem a derivação dos resultados de outra tabela. É o mecanismo de banco de dados que faz todo o trabalho duro.
Se você não precisar de uma navegação recorde por recorde, poderá recuperar um lote inteiro de registros de uma só vez:-
$ frequentUsers = $ user -> find ([ ' visits>? ' , 3 ],[ ' order ' => ' userID ' ]);
A sintaxe de consulta do Jig Mapper tem uma ligeira semelhança:-
$ frequentUsers = $ user -> find ([ ' @visits>? ' , 3 ],[ ' order ' => ' userID ' ]);
O código equivalente usando o MongoDB Mapper:-
$ frequentUsers = $ user -> find ([ ' visits ' =>[ ' $gt ' => 3 ]],[ ' userID ' => 1 ]);
O método find()
pesquisa a tabela users
para registros que correspondem aos critérios, classifica o resultado do userID
e retorna o resultado como uma matriz de objetos de mapeador. find('visits>3')
é diferente da load('visits>3')
. Este último se refere ao objeto $user
. find()
não tem nenhum efeito no skip()
.
IMPORTANTE: Declarar uma condição vazia, nula ou uma sequência de comprimento zero como o primeiro argumento de find()
ou load()
recuperará todos os registros. Certifique -se de saber o que está fazendo - você pode exceder o PHP Memory_limit em grandes tabelas ou coleções.
O método find()
tem a seguinte sintaxe:-
find (
$ criteria ,
[
' group ' => ' foo ' ,
' order ' => ' foo,bar ' ,
' limit ' => 5 ,
' offset ' => 0
]
);
encontre () retorna uma variedade de objetos. Cada objeto é um mapeador de um registro que corresponde aos critérios especificados.
$ place = new DB SQL Mapper ( $ db , ' places ' );
$ list = $ place -> find ( ' state="New York" ' );
foreach ( $ list as $ obj )
echo $ obj -> city . ' , ' . $ obj -> country ;
Se você precisar converter um objeto de mapeador em uma matriz associativa, use o método cast()
:-
$ array = $ place -> cast ();
echo $ array [ ' city ' ]. ' , ' . $ array [ ' country ' ];
Para recuperar o número de registros em uma tabela que corresponde a uma determinada condição, use o método count()
.
if (! $ user -> count ([ ' visits>? ' , 10 ]))
echo ' We need a better ad campaign! ' ;
Há também um método select()
que é semelhante ao find()
, mas fornece mais controle de granulação fina sobre os campos retornados. Tem uma sintaxe do tipo SQL:-
select (
' foo, bar, MIN(baz) AS lowest ' ,
' foo > ? ' ,
[
' group ' => ' foo, bar ' ,
' order ' => ' baz ASC ' ,
' limit ' => 5 ,
' offset ' => 3
]
);
Muito parecido com o método find()
, select()
não altera o conteúdo do objeto de mapeador. Serve apenas como um método de conveniência para consultar uma tabela mapeada. O valor de retorno de ambos os métodos é uma matriz de objetos de mapeador. Usar dry()
para determinar se um registro foi encontrado por um desses métodos é inadequado. Se nenhum registro corresponde aos critérios find()
ou select()
, o valor de retorno será uma matriz vazia.
Se você deseja descobrir quais instruções SQL emitidas diretamente por sua aplicação (ou indiretamente através de objetos de mapeador) estão causando gargalos de desempenho, você pode fazê-lo com um simples:-
echo $ db -> log ();
O F3 acompanha todos os comandos emitidos para o driver de banco de dados SQL subjacente, bem como o tempo necessário para que cada instrução seja concluída - apenas as informações corretas necessárias para ajustar o desempenho do aplicativo.
Na maioria dos casos, você pode viver pelos confortos dados pelos métodos de mapeador de dados que discutimos até agora. Se você precisar da estrutura para fazer algum trabalho pesado, poderá estender o mapeador SQL declarando suas próprias aulas com métodos personalizados- mas não pode evitar ficar com as mãos oleosas em algum SQL hardcore:-
class Vendor extends DB SQL Mapper {
// Instantiate mapper
function __construct ( DB SQL $ db ) {
// This is where the mapper and DB structure synchronization occurs
parent :: __construct ( $ db , ' vendors ' );
}
// Specialized query
function listByCity () {
return $ this -> select (
' vendorID,name,city ' ,[ ' order ' => ' city DESC ' ]);
/ *
We could have done the the same thing with plain vanilla SQL : -
return $ this - > db - > exec (
'SELECT vendorID,name,city FROM vendors ' .
'ORDER BY city DESC;'
);
* /
}
}
$ vendor = new Vendor ;
$ vendor -> listByCity ();
Estender os mapeadores de dados dessa maneira é uma maneira fácil de construir os modelos relacionados ao banco de dados do seu aplicativo.
Se você é útil com o SQL, provavelmente diria: tudo no ORM pode ser tratado com consultas SQL da velha escola. De fato. Podemos ficar sem os ouvintes de eventos adicionais usando gatilhos de banco de dados e procedimentos armazenados. Podemos realizar consultas relacionais com tabelas unidas. O ORM é apenas uma sobrecarga desnecessária. Mas o ponto é: os mapeadores de dados fornecem a funcionalidade adicional do uso de objetos para representar entidades do banco de dados. Como desenvolvedor, você pode escrever código mais rápido e ser mais produtivo. O programa resultante será mais limpo, se não for mais curto. Mas você terá que pesar os benefícios contra o compromisso de velocidade - especialmente ao lidar com lojas de dados grandes e complexas. Lembre -se, todos os ORMs - não importa o quão finos sejam - sempre serão apenas mais uma camada de abstração. Eles ainda precisam passar o trabalho para os motores SQL subjacentes.
Por design, o ORMS da F3 não fornece métodos para conectar diretamente objetos entre si, ou seja, o SQL se junta - porque isso abre uma lata de vermes. Isso torna sua aplicação mais complexa do que deveria, e existe a tendência de objetos através de técnicas de busca de busca ansiosa ou preguiçosa de serem implementadas e até de sincronia devido à herança e polimorfismo de objetos (incompatibilidade de impedância) com as entidades do banco de dados que são mapeadas . Existem maneiras indiretas de fazê -lo no SQL Mapper, usando campos virtuais - mas você terá que fazer isso programaticamente e por seu próprio risco.
Se você estiver tentado a aplicar conceitos de OOP "puro" em seu aplicativo para representar todos os seus dados (porque "tudo é um objeto"), lembre -se de que os dados quase sempre vive mais tempo que o aplicativo. Seu programa já pode estar desatualizado muito antes de os dados perderem seu valor. Não adicione outra camada de complexidade em seu programa usando objetos e classes entrelaçados que se desviam demais do esquema e da estrutura física dos dados.
Antes de tecer vários objetos em seu aplicativo para manipular as tabelas subjacentes no seu banco de dados, pense sobre isso: criar visualizações para representar relacionamentos e gatilhos para definir o comportamento do objeto no mecanismo de banco de dados é mais eficiente. Os mecanismos de banco de dados relacionais são projetados para lidar com vistas, tabelas e gatilhos unidos. Eles não são lojas de dados idiotas. As tabelas unidas em uma visão aparecerão como uma única tabela, e o Fat Free pode mapear automaticamente uma visualização tão bem quanto uma tabela comum. As junções de replicação como objetos relacionais no PHP são mais lentas em comparação com o código da máquina do mecanismo de banco de dados, a álgebra relacional e a lógica de otimização. Além disso, ingressar nas tabelas repetidamente em nosso aplicativo é um sinal claro de que o design do banco de dados precisa ser auditado e as visualizações consideradas parte integrante da recuperação de dados. Se uma tabela de referências cruzadas de outra tabela com frequência, considere normalizar suas estruturas ou criar uma visualização. Em seguida, crie um objeto de mapeador para mapa automática dessa visualização. É mais rápido e requer menos esforço.
Considere esta exibição SQL criada dentro do seu mecanismo de banco de dados:-
CREATE VIEW combined AS
SELECT
projects . project_id AS project,
users . name AS name
FROM projects
LEFT OUTER JOIN users ON
projects . project_id = users . project_id AND
projects . user_id = users . user_id ;
O código do seu aplicativo se torna simples porque não precisa manter dois objetos de mapeador (um para a tabela de projetos e outro para os usuários) apenas para recuperar dados de duas tabelas unidas:-
$ combined = new DB SQL Mapper ( $ db , ' combined ' );
$ combined -> load ([ ' project=? ' , 123 ]);
echo $ combined -> name ;
Dica: use as ferramentas conforme projetadas. A FAT sem gordura já possui um ajudante SQL fácil de usar. Use -o se precisar de um martelo maior :) tente buscar um equilíbrio entre conveniência e desempenho. O SQL sempre será o seu fallback se você estiver trabalhando em estruturas de dados complexas e herdadas.
Os plug-ins nada mais são do que classes automáticas que usam o Framework embutido para estender os recursos e funcionalidade da F3. If you'd like to contribute, leave a note at the Fat-Free Discussion Area hosted by Google Groups or tell us about it in the FreeNode #fatfree
IRC channel. Someone else might be involved in a similar project. The framework community will appreciate it a lot if we unify our efforts.
There might be instances when you want to make your forms more secure against spam bots and malicious automated scripts. F3 provides a captcha()
method to generate images with random text that are designed to be recognizable only by humans.
$ img = new Image ();
$ img -> captcha ( ' fonts/CoolFont.ttf ' , 16 , 5 , ' SESSION.captcha_code ' );
$ img -> render ();
This example generates an random image based on your desired TrueType font. The fonts/
folder is a subfolder within application's UI
path. The second parameter indicates the font size, and the third argument defines the number of hexadecimal characters to generate.
The last argument represents an F3 variable name. This is where F3 will store the string equivalent of the CAPTCHA image. To make the string reload-safe, we specified a session variable:- SESSION.captcha_code
which maps to $_SESSION['captcha_code']
, which you can use later to verify whether the input element in the form submitted matches this string.
We've covered almost every feature available in the framework to run a stand-alone Web server. For most applications, these features will serve you quite well. But what do you do if your application needs data from another Web server on the network? F3 has the Web plugin to help you in this situation:-
$ web = new Web ;
$ request = $ web -> request ( ' http://www.google.com/ ' );
// another way to do it : -
$ request =Web:: instance ()-> request ( ' http://www.google.com/ ' );
This simple example sends an HTTP request to the page located at www.google.com and stores it in the $request
PHP variable. The request()
method returns an array containing the HTTP response such that $request['headers']
and $request['body']
represent the response headers and body, respectively. We could have saved the contents using the F3::set command, or echo'ed the output directly to our browser. Retrieving another HTML page on the net may not have any practical purpose. But it can be particularly useful in ReSTful applications, like querying a CouchDB server.
$ host = ' localhost:5984 ' ;
$ web -> request ( $ host . ' /_all_dbs ' ),
$ web -> request ( $ host . ' /testdb/ ' ,[ ' method ' => ' PUT ' ]);
You may have noticed that you can pass an array of additional options to the request()
method:-
$ web -> request (
' https://www.example.com:443? ' .
http_build_query (
[
' key1 ' => ' value1 ' ,
' key2 ' => ' value2 '
]
),
[
' headers ' =>[
' Accept: text/html,application/xhtml+xml,application/xml ' ,
' Accept-Language: en-us '
],
' follow_location ' => FALSE ,
' max_redirects ' => 30 ,
' ignore_errors ' => TRUE
]
);
If the framework variable CACHE
is enabled, and if the remote server instructs your application to cache the response to the HTTP request, F3 will comply with the request and retrieve the cached response each time the framework receives a similar request from your application, thus behaving like a browser.
Fat-Free will use whatever means are available on your Web server for the request()
method to run: PHP stream wrappers ( allow_url_fopen
), cURL module, or low-level sockets.
F3 has a utility for sending files to an HTTP client, ie fulfilling download requests. You can use it to hide the real path to your download files. This adds some layer of security because users won't be able to download files if they don't know the file names and their locations. Here's how it's done:-
$ f3 -> route ( ' GET /downloads/@filename ' ,
function ( $ f3 , $ args ) {
// send () method returns FALSE if file doesn ' t exist
if (!Web:: instance ()-> send ( ' /real/path/ ' . $ args [ ' filename ' ]))
// Generate an HTTP 404
$ f3 -> error ( 404 );
}
);
The request()
method can also be used in complex SOAP or XML-RPC applications, if you find the need for another Web server to process data on your computer's behalf - thus harnessing the power of distributing computing. W3Schools.com has an excellent tutorial on SOAP. On the other hand, TutorialsPoint.com gives a nice overview of XML-RPC.
Caching static Web pages - so the code in some route handlers can be skipped and templates don't have to be reprocessed - is one way of reducing your Web server's work load so it can focus on other tasks. You can activate the framework's cache engine by providing a third argument to the $f3->route()
method. Just specify the number of seconds before a cached Web page expires:-
$ f3 -> route ( ' GET /my_page ' , ' App->method ' , 60 );
Veja como funciona. In this example, when F3 detects that the URL /my_page
is accessed for the first time, it executes the route handler represented by the second argument and saves all browser output to the framework's built-in cache (server-side). A similar instruction is automatically sent to the user's Web browser (client-side), so that instead of sending an identical request to the server within the 60-second period, the browser can just retrieve the page locally. The framework uses the cache for an entirely different purpose - serving framework-cached data to other users asking for the same Web page within the 60-second time frame. It skips execution of the route handler and serves the previously-saved page directly from disk. When someone tries to access the same URL after the 60-second timer has lapsed, F3 will refresh the cache with a new copy.
Web pages with static data are the most likely candidates for caching. Fat-Free will not cache a Web page at a specified URL if the third argument in the $f3->route()
method is zero or unspecified. F3 conforms to the HTTP specifications: only GET and HEAD requests can be cached.
Here's an important point to consider when designing your application. Don't cache Web pages unless you understand the possible unwanted side-effects of the cache at the client-side. Make sure that you activate caching on Web pages that have nothing to do with the user's session state.
For example, you designed your site in such a way that all your Web pages have the menu options: "Home"
, "About Us"
, and "Login"
, displayed when a user is not logged into your application. You also want the menu options to change to: "Home"
, "About Us"
, and "Logout"
, once the user has logged in. If you instructed Fat-Free to cache the contents of "About Us"
page (which includes the menu options), it does so and also sends the same instruction to the HTTP client. Regardless of the user's session state, ie logged in or logged out, the user's browser will take a snapshot of the page at the session state it was in. Future requests by the user for the "About Us"
page before the cache timeout expires will display the same menu options available at that time the page was initially saved. Now, a user may have already logged in, but the menu options are still the same as if no such event occurred. That's not the kind of behavior we want from our application.
Some pointers:-
GET
routes only. It will not cache submitted forms!Don't activate the cache on Web pages that at first glance look static. In our example, the "About Us" content may be static, but the menu isn't."About Us"
page, make sure it's available only when a user is not logged in.CACHE
global variable so it points to that drive. This will make your application run like a Formula 1 race car. Note: Don't set the timeout value to a very long period until you're ready to roll out your application, ie the release or production state. Changes you make to any of your PHP scripts may not have the expected effect on the displayed output if the page exists in the framework cache and the expiration period has not lapsed. If you do alter a program that generates a page affected by the cache timer and you want these changes to take effect immediately, you should clear the cache by erasing the files in the cache/ directory (or whatever path the CACHE
global variable points to) . F3 will automatically refresh the cache if necessary. At the client-side, there's little you can do but instruct the user to clear the browser's cache or wait for the cache period to expire.
PHP needs to be set up correctly for the F3 cache engine to work properly. Your operating system timezone should be synchronized with the date.timezone setting in the php.ini
file.
Similar to routes, Fat-Free also allows you to cache database queries. Speed gains can be quite significant, specially when used on complex SQL statements that involve look-up of static data or database content that rarely changes. Activating the database query cache so the framework doesn't have to re-execute the SQL statements every time is as simple as adding a 3rd argument to the F3::sql command - the cache timeout. Por exemplo:-
$ db -> exec ( ' SELECT * from sizes; ' , NULL , 86400 );
If we expect the result of this database query to always be Small
, Medium
, and Large
within a 24-hour period, we specify 86400
seconds as the 2nd argument so Fat-Free doesn't have to execute the query more than once a day . Instead, the framework will store the result in the cache, retrieve it from the cache every time a request comes in during the specified 24-hour time frame, and re-execute the query when the timer lapses.
The SQL data mapper also uses the cache engine to optimize synchronization of table structures with the objects that represent them. The default is 60
seconds. If you make any changes to a table's structure in your database engine, you'll have to wait for the cache timer to expire before seeing the effect in your application. You can change this behavior by specifying a third argument to the data mapper constructor. Set it to a high value if you don't expect to make any further changes to your table structure.
$ user = new DB SQL Mapper ( $ db , ' users ' , 86400 );
By default, Fat-Free's cache engine is disabled. You can enable it and allow it to auto-detect APC, WinCache or XCache. If it cannot find an appropriate backend, F3 will use the filesystem, ie the tmp/cache/
folder:-
$ f3 -> set ( ' CACHE ' , TRUE );
Disabling the cache is as simple as:-
$ f3 -> set ( ' CACHE ' , FALSE );
If you wish to override the auto-detection feature, you can do so - as in the case of a Memcached back-end which F3 also supports:-
$ f3 -> set ( ' CACHE ' , ' memcache=localhost:11211 ' );
You can also use the cache engine to store your own variables. These variables will persist between HTTP requests and remain in cache until the engine receives instructions to delete them. To save a value in the cache:-
$ f3 -> set ( ' var ' , ' I want this value saved ' , 90 );
$f3->set()
method's third argument instructs the framework to save the variable in the cache for a 90-second duration. If your application issues a $f3->get('var')
within this period, F3 will automatically retrieve the value from cache. In like manner, $f3->clear('var')
will purge the value from both cache and RAM. If you want to determine if a variable exists in cache, `$f3->exists('var')); returns one of two possible values: FALSE if the framework variable passed does not exist in cache, or an integer representing the time the variable was saved (Un*x time in seconds, with microsecond precision).
Fat-Free also has a Javascript and CSS compressor available in the Web plug-in. It can combine all your CSS files into one stylesheet (or Javascript files into a single script) so the number of components on a Web page are decreased. Reducing the number of HTTP requests to your Web server results in faster page loading. First you need to prepare your HTML template so it can take advantage of this feature. Something like:-
< link rel =" stylesheet " type =" text/css "
href =" /minify/css?files=typo.css,grid.css " />
Do the same with your Javascript files:-
< script type =" text/javascript " src =" /minify/js?&files=underscore.js " >
</ script >
Of course we need to set up a route so your application can handle the necessary call to the Fat-Free CSS/Javascript compressor:-
$ f3 -> route ( ' GET /minify/@type ' ,
function ( $ f3 , $ args ) {
$ f3 -> set ( ' UI ' , $ args [ ' type ' ]. ' / ' );
echo Web:: instance ()-> minify ( $ _GET [ ' files ' ]);
},
3600
);
And that's all there is to it! minify()
reads each file ( typo.css
and grid.css
in our CSS example, underscore.js
in our Javascript example), strips off all unnecessary whitespaces and comments, combines all of the related items as a single Web page component, and attaches a far-future expiry date so the user's Web browser can cache the data. It's important that the PARAMS.type
variable base points to the correct path. Otherwise, the URL rewriting mechanism inside the compressor won't find the CSS/Javascript files.
In our examples, the framework sends a far-future expiry date to the client's Web browser so any request for the same CSS or Javascript block will come from the user's hard drive. On the server side, F3 will check each request and see if the CSS or Javascript blocks have already been cached. The route we specified has a cache refresh period of 3600
seconds. Additionally, if the Web browser sends an If-Modified-Since
request header and the framework sees the cache hasn't changed, F3 just sends an HTTP 304 Not Modified
response so no content is actually delivered. Without the If-Modified-Since
header, Fat-Free renders the output from the cached file if available. Otherwise, the relevant code is executed.
Tip: If you're not modifying your Javascript/CSS files frequently (as it would be if you're using a Javascript library like jQuery, MooTools, Dojo, etc.), consider adding a cache timer to the route leading to your Javascript/CSS minify handler (3rd argument of F3::route()) so Fat-Free doesn't have compress and combine these files each time such a request is received.
Want to make your site run even faster? Fat-Free works best with either Alternative PHP Cache (APC), XCache, or WinCache. These PHP extensions boost performance of your application by optimizing your PHP scripts (including the framework code).
A fast application that processes all HTTP requests and responds to them at the shortest time possible is not always a good idea - specially if your bandwidth is limited or traffic on your Web site is particularly heavy. Serving pages ASAP also makes your application vulnerable to Denial-of-Service (DOS) attacks. F3 has a bandwidth throttling feature that allows you to control how fast your Web pages are served. You can specify how much time it should take to process a request:-
$ f3 -> route ( ' /throttledpage ' , ' MyApp->handler ' , 0 , 128 );
In this example, the framework will serve the Web page at a rate of 128KiBps.
Bandwidth throttling at the application level can be particularly useful for login pages. Slow responses to dictionary attacks is a good way of mitigating this kind of security risk.
Robust applications are the result of comprehensive testing. Verifying that each part of your program conforms to the specifications and lives up to the expectations of the end-user means finding bugs and fixing them as early as possible in the application development cycle.
If you know little or nothing about unit testing methodologies, you're probably embedding pieces of code directly in your existing program to help you with debugging. That of course means you have to remove them once the program is running. Leftover code fragments, poor design and faulty implementation can creep up as bugs when you roll out your application later.
F3 makes it easy for you to debug programs - without getting in the way of your regular thought processes. The framework does not require you to build complex OOP classes, heavy test structures, and obtrusive procedures.
A unit (or test fixture) can be a function/method or a class. Let's have a simple example:-
function hello () {
return ' Hello, World ' ;
}
Save it in a file called hello.php
. Now how do we know it really runs as expected? Let's create our test procedure:-
$ f3 = require ( ' lib/base.php ' );
// Set up
$ test = new Test ;
include ( ' hello.php ' );
// This is where the tests begin
$ test -> expect (
is_callable ( ' hello ' ),
' hello() is a function '
);
// Another test
$ hello = hello ();
$ test -> expect (
! empty ( $ hello ),
' Something was returned '
);
// This test should succeed
$ test ->expect
is_string ( $ hello ),
' Return value is a string '
);
// This test is bound to fail
$ test -> expect (
strlen ( $ hello )== 13 ,
' String length is 13 '
);
// Display the results ; not MVC but let ' s keep it simple
foreach ( $ test -> results () as $ result ) {
echo $ result [ ' text ' ]. ' <br /> ' ;
if ( $ result [ ' status ' ])
echo ' Pass ' ;
else
echo ' Fail ( ' . $ result [ ' source ' ]. ' ) ' ;
echo ' <br /> ' ;
}
Save it in a file called test.php
. This way we can preserve the integrity of hello.php
.
Now here's the meat of our unit testing process.
F3's built-in Test
class keeps track of the result of each expect()
call. The output of $test->results()
is an array of arrays with the keys text
(mirroring argument 2 of expect()
), status
(boolean representing the result of a test), and source
(file name/line number of the specific test) to aid in debugging.
Fat-Free gives you the freedom to display test results in any way you want. You can have the output in plain text or even a nice-looking HTML template. So how do we run our unit test? If you saved test.php
in the document root folder, you can just open your browser and specify the address http://localhost/test.php
. Isso é tudo que há para fazer.
F3 gives you the ability to simulate HTTP requests from within your PHP program so you can test the behavior of a particular route. Here's a simple mock request:-
$ f3 -> mock ( ' GET /test?foo=bar ' );
To mock a POST request and submit a simulated HTML form:-
$ f3 -> mock ( ' POST /test ' ,[ ' foo ' => ' bar ' ]);
Once you get the hang of testing the smallest units of your application, you can then move on to the bigger components, modules, and subsystems - checking along the way if the parts are correctly communicating with each other. Testing manageable chunks of code leads to more reliable programs that work as you expect, and weaves the testing process into the fabric of your development cycle. The question to ask yourself is:- Have I tested all possible scenarios? More often than not, those situations that have not been taken into consideration are the likely causes of bugs. Unit testing helps a lot in minimizing these occurrences. Even a few tests on each fixture can greatly reduce headaches. On the other hand, writing applications without unit testing at all invites trouble.
string AGENT
Mozilla/5.0 (Linux; Android 4.2.2; Nexus 7) AppleWebKit/537.31
. bool AJAX
TRUE
if an XML HTTP request is detected, FALSE
otherwise. string AUTOLOAD
|
), comma ( ,
), or semi-colon ( ;
) as path separator. string BASE
index.php
main/front controller. string BODY
bool/string CACHE
'memcache=localhost'
(and the PHP memcache module is present), F3 auto-detects the presence of APC, WinCache and XCache and uses the first available PHP module if set to TRUE. If none of these PHP modules are available, a filesystem-based backend is used (default directory: tmp/cache
). The framework disables the cache engine if assigned a FALSE
value. bool CASELESS
FALSE
to make it case-sensitive. array COOKIE, GET, POST, REQUEST, SESSION, FILES, SERVER, ENV
integer DEBUG
string DNSBL
403 Forbidden
error if the user's IPv4 address is listed on the specified server(s). array DIACRITICS
string ENCODING
UTF-8
. array ERROR
ERROR.code
is the HTTP status code. ERROR.status
contains a brief description of the error. ERROR.text
provides more detail. For HTTP 500 errors, use ERROR.trace
to retrieve the stack trace. bool ESCAPE
string EXEMPT
string FALLBACK
bool HALT
array HEADERS
bool HIGHLIGHT
TRUE
(requires code.css
stylesheet). string HOST
$_SERVER['SERVER_NAME']
is not available, return value of gethostname()
is used. string IP
array JAR
string LANGUAGE
LOCALES
. If set to NULL
, language is auto-detected from the HTTP Accept-Language
request header. string LOCALES
string LOGS
mixed ONERROR
string PACKAGE
array PARAMS
route()
pattern. PARAMS.0
contains the captured URL relative to the Web root. string PATTERN
string PLUGINS
base.php
. int PORT
string PREFIX
bool QUIET
bool RAW
BODY
. Should be TRUE when processing large data coming from php://input
which will not fit in memory. Default value: FALSE
string REALM
string RESPONSE
QUIET
setting. string ROOT
array ROUTES
string SCHEME
http
or https
. string SERIALIZER
php
, unless PHP igbinary
extension is auto-detected. Assign json
if desired. string TEMP
tmp/
folder inside the Web root. Adjust accordingly to conform to your site's security policies. string TZ
date_default_timezone_set()
function. string UI
View
and Template
classes' render()
method. Default value is the Web root. Accepts a pipe ( |
), comma ( ,
), or semi-colon ( ;
) as separator for multiple paths. callback UNLOAD
string UPLOADS
string URI
string VERB
string VERSION
@token
@token
with value of equivalent F3 variable. {{ mixed expr }}
expr
may include template tokens, constants, operators (unary, arithmetic, ternary and relational), parentheses, data type converters, and functions. If not an attribute of a template directive, result is echoed. {{ string expr | raw }}
expr
. F3 auto-escapes strings by default. {{ string expr | esc }}
expr
. This is the default framework behavior. The | esc
suffix is only necessary if ESCAPE
global variable is set to FALSE
. {{ string expr, arg1, ..., argN | format }}
expr
and pass the comma-separated arguments, where arg1, ..., argn
is one of:- 'date'
, 'time'
, 'number, integer'
, 'number, currency'
, or 'number, percent'
. <include
[ if="{{ bool condition }}" ]
href="{{ string subtemplate }}"
/>
subtemplate
and insert at current position in template if optional condition is TRUE
. <exclude>text-block</exclude>
text-block
at runtime. Used for embedding comments in templates. <ignore>text-block</ignore>
text-block
as-is, without interpretation/modification by the template engine. <check if="{{ bool condition }}">
<true>true-block</true>
<false>false-block</false>
</check>
TRUE
, then true-block
is rendered. Otherwise, false-block
is used. <loop
from="{{ statement }}"
to="{{ bool expr }}"
[ step="{{ statement }}" ]>
text-block
</loop>
from
statement once. Check if the expression in the to
attribute is TRUE
, render text-block
and evaluate step
statement. Repeat iteration until to
expression is FALSE
. <repeat
group="{{ array @group|expr }}"
[ key="{{ scalar @key }}" ]
value="{{ mixed @value }}"
[ counter="{{ scalar @key }}" ]>
text-block
</repeat>
text-block
as many times as there are elements in the array variable @group
or the expression expr
. @key
and @value
function in the same manner as the key-value pair in the equivalent PHP foreach()
statement. Variable represented by key
in counter
attribute increments by 1
with every iteration. <switch expr="{{ scalar expr }}">
<case value="{{ scalar @value|expr }}" break="{{ bool TRUE|FALSE }}">
text-block
</case>
.
.
.
</switch>
{* text-block *}
<exclude>
.The most up-to-date documentation is located at http://fatfreeframework.com/. It contains examples of usage of the various framework components.
Technical support is available at the official discussion forum: https://groups.google.com/forum/#!forum/f3-framework
. If you need live support, you can talk to the development team and other members of the F3 community via Slack or IRC. We're on the FreeNode #fatfree
channel ( chat.freenode.net
). Visit http://webchat.freenode.net/
to join the conversation. You can also download the Firefox Chatzilla add-on or Pidgin if you don't have an IRC client so you can participate in the live chat. You can also find help at Stack Overflow
F3 uses Git for version control. To clone the latest code repository on GitHub:
git clone git://github.com/bcosca/fatfree-core.git
If all you want is a zipball of our test bench with all unit tests, grab it here .
To file a bug report, visit https://github.com/bcosca/fatfree-core/issues
.
Fat-Free Framework is free and released as open source software covered by the terms of the GNU Public License (GPL v3). You may not use the software, documentation, and samples except in compliance with the license. If the terms and conditions of this license are too restrictive for your use, alternative licensing is available for a very reasonable fee.
If you feel that this software is one great weapon to have in your programming arsenal, it saves you a lot of time and money, use it for commercial gain or in your business organization, please consider making a donation to the project. A significant amount of time, effort, and money has been spent on this project. Your donations help keep this project alive and the development team motivated. Donors and sponsors get priority support (24-hour response time on business days).
The Fat-Free Framework is community-driven software. It can't be what it is today without the help and support from the following people and organizations:
Special thanks to the selfless others who expressed their desire to remain anonymous, yet share their time, contribute code, send donations, promote the framework to a wider audience, as well as provide encouragement and regular financial assistance. Their generosity is F3's prime motivation.
By making a donation to this project you signify that you acknowledged, understood, accepted, and agreed to the terms and conditions contained in this notice. Your donation to the Fat-Free Framework project is voluntary and is not a fee for any services, goods, or advantages, and making a donation to the project does not entitle you to any services, goods, or advantages. We have the right to use the money you donate to the Fat-Free Framework project in any lawful way and for any lawful purpose we see fit and we are not obligated to disclose the way and purpose to any party unless required by applicable law. Although Fat-Free Framework is free software, to our best knowledge this project does not have any tax-exempt status. The Fat-Free Framework project is neither a registered non-profit corporation nor a registered charity in any country. Your donation may or may not be tax-deductible; please consult this with your tax advisor. We will not publish/disclose your name and e-mail address without your consent, unless required by applicable law. Your donation is non-refundable.
Copyright (c) 2009-2022 F3::Factory/Bong Cosca <[email protected]>
Ei cara! Me ajude por alguns!