Un micromarco PHP potente pero fácil de usar diseñado para ayudarle a crear aplicaciones web dinámicas y robustas, ¡rápido!
Condensado en un único archivo de ~65 KB, F3 (como lo llamamos con cariño) le brinda una base sólida, una base de código madura y un enfoque sensato para escribir aplicaciones web. Debajo del capó hay un kit de herramientas de desarrollo web fácil de usar, un motor de caché y enrutamiento de URL de alto rendimiento, resaltado de código integrado y soporte para aplicaciones multilingües. Es liviano, fácil de usar y rápido. Sobre todo, no se interpone en tu camino.
Ya seas un programador PHP novato o experto, F3 te pondrá en funcionamiento en poco tiempo. Sin procedimientos de instalación innecesarios y laboriosos. No se requiere configuración compleja. Sin estructuras de directorio complicadas. ¡No hay mejor momento para empezar a desarrollar aplicaciones web de forma sencilla que ahora!
F3 admite bases de datos SQL y NoSQL disponibles en el mercado: MySQL, SQLite, MSSQL/Sybase, PostgreSQL, DB2 y MongoDB. También viene con potentes mapeadores relacionales de objetos para la abstracción y el modelado de datos que son tan livianos como el marco. No se necesita configuración.
Eso no es todo. F3 incluye otros complementos opcionales que amplían sus capacidades: -
A diferencia de otros marcos, F3 pretende ser utilizable, algo que no es habitual.
La filosofía detrás del marco y su enfoque de la arquitectura de software apunta al minimalismo en los componentes estructurales, evitando la complejidad de las aplicaciones y logrando un equilibrio entre la elegancia del código, el rendimiento de las aplicaciones y la productividad del programador.
F3 tiene una arquitectura estable de clase empresarial. Rendimiento inmejorable, funciones fáciles de usar y tamaño liviano. ¿Qué más se puede pedir? Para obtener este paquete, simplemente descárguelo o visite el repositorio fatfree-core para encontrar la última versión de Edge.
Para todos los usuarios de compositores:
composer create-project bcosca/fatfree
composer require bcosca/fatfree-core
Se recomienda encarecidamente que los usuarios experimentados desarrollen nuevas aplicaciones con la última versión para aprovechar una base de código actualizada y mejoras continuas.
La guía de usuario más actualizada y la documentación API detallada con muchos ejemplos de código y una guía gráfica se pueden encontrar en fatfreeframework.com/.
¡Por supuesto, esta práctica referencia en línea funciona con F3! Muestra la capacidad y el rendimiento del marco. Compruébalo ahora. Si desea leerlo directamente en github, puede encontrar el contenido del sitio web en github.com/F3Community/F3com-data
Un diseñador sabe que ha alcanzado la perfección no cuando no queda nada que añadir, sino cuando no queda nada que quitar. -- Antoine de Saint-Exupéry
Fat-Free Framework facilita la creación de sitios web completos en un santiamén. Con el mismo poder y brevedad que las bibliotecas y kits de herramientas de Javascript modernos, F3 le ayuda a escribir programas PHP más atractivos y confiables. Con un vistazo a su código fuente PHP, cualquiera encontrará fácil de entender cuánto puede lograr en tan pocas líneas de código y cuán poderosos son los resultados.
F3 es uno de los marcos mejor documentados que existen. Aprenderlo cuesta casi nada. Sin un conjunto estricto de estructuras de directorios difíciles de navegar ni pasos de programación molestos. No hay un montón de opciones de configuración solo para mostrar 'Hello, World'
en su navegador. Fat-Free le brinda mucha libertad (y estilo) para realizar más trabajo con facilidad y en menos tiempo.
El enfoque declarativo de programación de F3 facilita la comprensión del código PHP tanto para principiantes como para expertos. Si está familiarizado con el lenguaje de programación Ruby, notará el parecido entre el micromarco Fat-Free y Sinatra porque ambos emplean un lenguaje simple de dominio específico para servicios web ReSTful. Pero a diferencia de Sinatra y sus encarnaciones de PHP (Fitzgerald, Limonade, Glue, por nombrar algunos), Fat-Free va más allá de simplemente manejar rutas y solicitudes. Las vistas pueden tener cualquier formato, como texto sin formato, HTML, XML o un mensaje de correo electrónico. El marco viene con un motor de plantillas rápido y fácil de usar. F3 también funciona a la perfección con otros motores de plantillas, incluidos Twig, Smarty y el propio PHP. Los modelos se comunican con los mapeadores de datos de F3 y el asistente SQL para interacciones más complejas con varios motores de bases de datos. Otros complementos amplían aún más la funcionalidad básica. Es un marco de desarrollo web total, ¡con mucha potencia!
Descomprima el contenido del paquete de distribución en cualquier lugar de su disco duro. De forma predeterminada, el archivo de marco y los complementos opcionales se encuentran en la ruta lib/
. Organice las estructuras de sus directorios como desee. Puede mover las carpetas predeterminadas a una ruta a la que no se pueda acceder desde la Web para mayor seguridad. Elimine los complementos que no necesita. Siempre podrás restaurarlos más tarde y F3 detectará su presencia automáticamente.
Importante: si su aplicación utiliza APC, Memcached, WinCache, XCache o un caché de sistema de archivos, primero borre todas las entradas de caché antes de sobrescribir una versión anterior del marco con una nueva.
Asegúrate de estar ejecutando la versión correcta de PHP. F3 no admite versiones anteriores a PHP 7.2. Obtendrá errores de sintaxis (falsos positivos) por todas partes porque las nuevas construcciones de lenguaje y cierres/funciones anónimas no son compatibles con versiones obsoletas de PHP. Para averiguarlo, abra su consola ( bash
shell en GNU/Linux o cmd.exe
en Windows):-
/path/to/php -v
PHP le permitirá saber qué versión particular está ejecutando y debería obtener algo similar a esto:-
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
Actualice si es necesario y regrese aquí si ha dado el salto a PHP 7.4 o una versión posterior. Fatfree necesita al menos PHP 7.2 para funcionar. Si necesita un proveedor de servicios de hosting, pruebe uno de estos servicios:
Es hora de empezar a escribir nuestra primera aplicación: -
$ f3 = require ( ' path/to/base.php ' );
$ f3 -> route ( ' GET / ' ,
function () {
echo ' Hello, world! ' ;
}
);
$ f3 -> run ();
Anteponga base.php
en la primera línea con la ruta adecuada. Guarde el fragmento de código anterior como index.php
en su carpeta raíz web. Hemos escrito nuestra primera página web.
¿Usando compositor? Luego simplemente ejecute composer require bcosca/fatfree
y use lo siguiente:
require ' vendor/autoload.php ' ;
$ f3 = Base:: instance ();
$ f3 -> route ( ' GET / ' ,
function () {
echo ' Hello, world! ' ;
}
);
$ f3 -> run ();
El primer comando le dice al intérprete de PHP que desea que las funciones y características del marco estén disponibles para su aplicación. El método $f3->route()
informa a Fat-Free que hay una página web disponible en la URL relativa indicada por la barra diagonal ( /
). Cualquiera que visite su sitio ubicado en http://www.example.com/
verá el mensaje 'Hello, world!'
mensaje porque la URL /
es equivalente a la página raíz. Para crear una ruta que se ramifique desde la página raíz, como http://www.example.com/inside/
, puede definir otra ruta con una simple cadena GET /inside
.
La ruta descrita anteriormente le dice al marco que muestre la página solo cuando recibe una solicitud de URL utilizando el método HTTP GET
. Los sitios web más complejos que contienen formularios utilizan otros métodos HTTP como POST
, y también puedes implementarlo como parte de una especificación $f3->route()
.
Si el marco ve una solicitud entrante para su página web ubicada en la URL raíz /
, automáticamente enrutará la solicitud a la función de devolución de llamada, que contiene el código necesario para procesar la solicitud y representar el contenido HTML apropiado. En este ejemplo, simplemente enviamos la cadena 'Hello, world!'
al navegador web del usuario.
Así que hemos establecido nuestra primera ruta. Pero eso no servirá de mucho, excepto hacerle saber a F3 que hay un proceso que lo manejará y que hay algo de texto para mostrar en el navegador web del usuario. Si tiene muchas más páginas en su sitio, deberá configurar rutas diferentes para cada grupo. Por ahora, hagámoslo simple. Para indicarle al marco que comience a esperar solicitudes, emitimos el comando $f3->run()
.
¿No puedes ejecutar el ejemplo? Si tiene problemas para ejecutar este sencillo programa en su servidor, es posible que deba modificar un poco la configuración de su servidor web. Eche un vistazo a la configuración de muestra de Apache en la siguiente sección (junto con los equivalentes de Nginx y Lighttpd).
¿Aún tienes problemas? Asegúrese de que $f3 = require('path/to/base.php');
La asignación viene antes de cualquier salida en su script. base.php
modifica los encabezados HTTP, por lo que cualquier carácter que se envíe al navegador antes de esta asignación provocará errores.
Nuestro primer ejemplo no fue demasiado difícil de digerir, ¿verdad? Si desea un poco más de sabor en su sopa sin grasa, inserte otra ruta antes del comando $f3->run()
:-
$ f3 -> route ( ' GET /about ' ,
function () {
echo ' Donations go to a local charity... us! ' ;
}
);
¿No quieres saturar el espacio de nombres global con nombres de funciones? Fat-Free reconoce diferentes formas de asignar controladores de ruta a clases y métodos de programación orientada a objetos: -
class WebPage {
function display () {
echo ' I cannot object to an object ' ;
}
}
$ f3 -> route ( ' GET /about ' , ' WebPage->display ' );
Las solicitudes HTTP también se pueden enrutar a métodos de clase estática: -
$ f3 -> route ( ' GET /login ' , ' Auth::login ' );
Los argumentos pasados siempre se proporcionan 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 ' ];
}
}
Si el argumento de nombre proporcionado fuera foo (/hello/foo), se mostraría el siguiente resultado:
Hello foo
Como demostración del potente lenguaje de dominio específico (DSL) de Fat-Free, puede especificar una única ruta para manejar diferentes posibilidades:
$ f3 -> route ( ' GET /brew/@count ' ,
function ( $ f3 ) {
echo $ f3 -> get ( ' PARAMS.count ' ). ' bottles of beer on the wall. ' ;
}
);
Este ejemplo muestra cómo podemos especificar un token @count
para representar parte de una URL. El marco servirá cualquier URL de solicitud que coincida con el prefijo /brew/
, como /brew/99
, /brew/98
, etc. Esto mostrará '99 bottles of beer on the wall'
y '98 bottles of beer on the wall'
, respectivamente. Fat-Free también aceptará una solicitud de página para /brew/unbreakable
. (Espere que esto muestre 'unbreakable bottles of beer on the wall'
). Cuando se especifica dicha ruta dinámica, Fat-Free completa automáticamente la variable de matriz global PARAMS
con el valor de las cadenas capturadas en la URL. La llamada $f3->get()
dentro de la función de devolución de llamada recupera el valor de una variable del marco. Sin duda, puede aplicar este método en su código como parte de la presentación o la lógica empresarial. Pero discutiremos eso con mayor detalle más adelante.
Tenga en cuenta que Fat-Free entiende la notación de puntos de matriz. Puede utilizar la notación regular PARAMS['count']
en su lugar en el código, que es propensa a errores tipográficos y llaves desequilibradas. En vistas y plantillas, el marco permite la notación @PARAMS.count
que es algo similar a Javascript. (Cubriremos las vistas y las plantillas más adelante).
Aquí hay otra forma de acceder a tokens en un patrón de solicitud: -
$ f3 -> route ( ' GET /brew/@count ' ,
function ( $ f3 , $ params ) {
echo $ params [ ' count ' ]. ' bottles of beer on the wall. ' ;
}
);
Puedes usar el asterisco ( *
) para aceptar cualquier URL después de la ruta /brew
, si realmente no te importa el resto de la ruta:-
$ f3 -> route ( ' GET /brew/* ' ,
function () {
echo ' Enough beer! We always end up here. ' ;
}
);
Un punto importante a considerar: se confundirá con Fat-Free (y con usted mismo) si tiene GET /brew/@count
y GET /brew/*
juntos en la misma aplicación. Utilice uno u otro. Otra cosa: Fat-Free ve GET /brew
como algo separado y distinto de la ruta GET /brew/@count
. Cada uno puede tener diferentes controladores de ruta.
Espere un segundo: en todos los ejemplos anteriores, nunca creamos ningún directorio en nuestro disco duro para almacenar estas rutas. La respuesta corta: no es necesario. Todas las rutas F3 son virtuales. No reflejan la estructura de carpetas de nuestro disco duro. Si tiene programas o archivos estáticos (imágenes, CSS, etc.) que no utilizan el marco (siempre que las rutas a estos archivos no entren en conflicto con ninguna ruta definida en su aplicación), el software de su servidor web los entregará al navegador del usuario, siempre que el servidor esté configurado correctamente.
Cuando defines una ruta, puedes asignarle un nombre. Utilice el nombre de la ruta en su código y plantillas en lugar de una URL escrita. Luego, si necesita cambiar sus URL para complacer a los señores del marketing, solo necesita realizar el cambio donde se definió la ruta. Los nombres de las rutas deben seguir las reglas de nomenclatura de variables de PHP (sin puntos, guiones ni guiones).
Nombramos una ruta:-
$ f3 -> route ( ' GET @beer_list: /beer ' , ' Beer->list ' );
El nombre se inserta después de la ruta VERBO ( GET
en este ejemplo) precedido por un símbolo @
y separado de la parte de la URL por dos puntos :
. Puede insertar un espacio después de los dos puntos si eso facilita la lectura de su código (como se muestra aquí).
Para acceder a la ruta nombrada en una plantilla, obtenga el valor de la ruta nombrada como clave de la matriz de colmena ALIASES
: -
< a href =" {{ @ALIASES.beer_list }} " > View beer list </ a >
Para redirigir al visitante a una nueva URL, llame a la ruta nombrada dentro del método reroute()
como: -
// a named route is a string value
$ f3 -> reroute ( ' @beer_list ' ); // note the single quotes
Si usa tokens en su ruta, F3 reemplazará esos tokens con su valor actual. Si desea cambiar el valor del token antes de llamar a la redirección, páselo como 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) ' );
Recuerde urlencode()
sus argumentos si tiene caracteres que no cumplen con las pautas RFC 1738 para URL bien formadas.
La última versión estable de PHP tiene su propio servidor web integrado. Inícielo usando la siguiente configuración: –
php -S localhost:80 -t /var/www/
El comando anterior comenzará a enrutar todas las solicitudes a la raíz web /var/www
. Si se recibe una solicitud HTTP entrante para un archivo o carpeta, PHP la buscará dentro de la raíz web y la enviará al navegador si la encuentra. De lo contrario, PHP cargará el index.php
predeterminado (que contiene su código habilitado para F3).
Si está utilizando Apache, asegúrese de activar el módulo de reescritura de URL (mod_rewrite) en su archivo apache.conf (o httpd.conf). También debe crear un archivo .htaccess que contenga lo siguiente: –
# 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]
El script le dice a Apache que cada vez que llega una solicitud HTTP y si no se puede encontrar ningún archivo físico ( !-f
), ruta ( !-d
) o enlace simbólico ( !-l
), debe transferir el control a index.php
, que contiene nuestro controlador principal/frontal, y que a su vez, invoca el marco.
El .htaccess file
que contiene las directivas de Apache mencionadas anteriormente siempre debe estar en la misma carpeta que index.php
.
También necesita configurar Apache para que conozca la ubicación física de index.php
en su disco duro. Una configuración típica es: -
DocumentRoot " /var/www/html "
< Directory "/var/www/html">
Options -Indexes +FollowSymLinks +Includes
AllowOverride All
Order allow,deny
Allow from All
</ Directory >
Si está desarrollando varias aplicaciones simultáneamente, una configuración de host virtual es más fácil de administrar: –
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
y site2.com
en nuestro ejemplo) debe aparecer en su archivo /etc/hosts
. En Windows, debes editar C:/WINDOWS/system32/drivers/etc/hosts
. Es posible que sea necesario reiniciar para efectuar los cambios. Luego puede apuntar su navegador web a la dirección http://site1.com
o http://site2.com
. Los hosts virtuales hacen que sus aplicaciones sean mucho más fáciles de implementar.
Para servidores Nginx, esta es la configuración recomendada (reemplace ip_address:port con la configuración PHP FastCGI de su entorno):-
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;
}
}
Los servidores Lighttpd están configurados de manera similar: -
$HTTP["host"] =~ "www.example.com$" {
url.rewrite-once = ( "^/(.*?)(?.+)?$"=>"/index.php/$1?$2" )
server.error-handler-404 = "/index.php"
}
Instale el módulo de reescritura de URL y el marco .NET apropiado correspondiente a su versión de Windows. Luego cree un archivo llamado web.config
en la raíz de su aplicación con el siguiente contenido:
<?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>
Así que volvamos a la codificación. Puede declarar una página obsoleta y redirigir a sus visitantes a otro sitio/página:-
$ f3 -> route ( ' GET|HEAD /obsoletepage ' ,
function ( $ f3 ) {
$ f3 -> reroute ( ' /newpage ' );
}
);
Si alguien intenta acceder a la URL http://www.example.com/obsoletepage
mediante una solicitud HTTP GET o HEAD, el marco redirige al usuario a la URL: http://www.example.com/newpage
como se muestra en la ejemplo anterior. También puede redirigir al usuario a otro sitio, como $f3->reroute('http://www.anotherexample.org/');
.
El cambio de ruta puede resultar especialmente útil cuando necesita realizar algunos trabajos de mantenimiento en su sitio. Puede tener un controlador de ruta que informe a sus visitantes que su sitio está fuera de línea por un período breve.
Las redirecciones HTTP son indispensables pero también pueden resultar costosas. En la medida de lo posible, absténgase de usar $f3->reroute()
para enviar a un usuario a otra página en el mismo sitio web si puede dirigir el flujo de su aplicación invocando la función o método que maneja la ruta de destino. Sin embargo, este enfoque no cambiará la URL en la barra de direcciones del navegador web del usuario. Si este no es el comportamiento que desea y realmente necesita enviar a un usuario a otra página, en casos como el envío exitoso de un formulario o después de que un usuario haya sido autenticado, Fat-Free envía un encabezado HTTP 302 Found
. Para todos los demás intentos de redirigir a otra página o sitio, el marco envía un encabezado HTTP 301 Moved Permanently
.
En tiempo de ejecución, Fat-Free genera automáticamente un error HTTP 404 cada vez que ve que una solicitud HTTP entrante no coincide con ninguna de las rutas definidas en su aplicación. Sin embargo, hay casos en los que es necesario activarlo usted mismo.
Tomemos, por ejemplo, una ruta definida como GET /dogs/@breed
. La lógica de su aplicación puede implicar buscar en una base de datos e intentar recuperar el registro correspondiente al valor de @breed
en la solicitud HTTP entrante. Dado que Fat-Free aceptará cualquier valor después del prefijo /dogs/
debido a la presencia del token @breed
, mostrar un mensaje HTTP 404 Not Found
mediante programación se vuelve necesario cuando el programa no encuentra ninguna coincidencia en nuestra base de datos. Para hacer eso, use el siguiente comando: -
$ f3 -> error ( 404 );
La arquitectura de Fat-Free se basa en el concepto de que los URI HTTP representan recursos web abstractos (no limitados a HTML) y cada recurso puede pasar de un estado de aplicación a otro. Por esta razón, F3 no tiene restricciones en la forma de estructurar su aplicación. Si prefiere utilizar el patrón Modelo-Vista-Controlador, F3 puede ayudarle a compartimentar los componentes de su aplicación para ceñirse a este paradigma. Por otro lado, el marco también admite el patrón Recursos-Método-Representación y su implementación es más sencilla.
Aquí hay un ejemplo de una interfaz ReST: -
class Item {
function get () {}
function post () {}
function put () {}
function delete () {}
}
$ f3 = require ( ' lib/base.php ' );
$ f3 -> map ( ' /cart/@item ' , ' Item ' );
$ f3 -> run ();
El método $f3->map()
de Fat-Free proporciona una interfaz ReST al mapear métodos HTTP en rutas a los métodos equivalentes de un objeto o una clase PHP. Si su aplicación recibe una solicitud HTTP entrante como GET /cart/123
, Fat-Free transferirá automáticamente el control al método get()
del objeto o clase. Por otro lado, una solicitud POST /cart/123
se enrutará al método post()
de la clase Item
.
Nota: Los navegadores no implementan los métodos HTTP PUT
y DELETE
en formularios HTML normales. Estos y otros métodos ReST ( HEAD
y CONNECT
) solo son accesibles a través de llamadas AJAX al servidor.
Si el marco recibe una solicitud HTTP para una ruta que se asigna a un método que no está implementado por una clase (quizás cometió un error en el mapeo de la ruta o el método aún no está escrito), genera un HTTP 405 Method Not Allowed
. Error HTTP 405 Method Not Allowed
.
Si un cliente solicita OPTIONS
HTTP para un recurso URL, F3 responde con los encabezados HTTP apropiados que indican qué métodos están permitidos para el recurso (HEAD, GET, PUT, etc.). El marco no asignará la solicitud OPTIONS
a una clase.
Fat-Free tiene una forma de cargar clases solo en el momento en que las necesita, para que no consuman más memoria de la que necesita un segmento particular de su aplicación. Y no es necesario escribir una larga lista de declaraciones include
o require
solo para cargar clases PHP guardadas en diferentes archivos y diferentes ubicaciones. El marco puede hacer esto automáticamente por usted. Simplemente guarde sus archivos (una clase por archivo) en una carpeta y dígale al marco que cargue automáticamente el archivo apropiado una vez que invoque un método en la clase: -
$ f3 -> set ( ' AUTOLOAD ' , ' autoload/ ' );
Puede asignar una ubicación diferente para sus clases cargadas automáticamente cambiando el valor de la variable global AUTOLOAD
. También puede tener múltiples rutas de carga automática. Si tiene sus clases organizadas y en diferentes carpetas, puede indicarle al marco que cargue automáticamente la clase apropiada cuando se llama a un método estático o cuando se crea una instancia de un objeto. Modifique la variable AUTOLOAD
de esta manera:-
$ f3 -> set ( ' AUTOLOAD ' , ' admin/autoload/; user/autoload/; default/ ' );
Importante: Excepto por la extensión .php, el nombre de la clase y el nombre del archivo deben ser idénticos para que el marco cargue automáticamente su clase correctamente. El nombre base de este archivo debe ser idéntico a su invocación de clase, por ejemplo, F3 buscará Foo/BarBaz.php
o foo/barbaz.php
cuando detecte una new FooBarBaz
en su aplicación.
AUTOLOAD
permite que las jerarquías de clases residan en subcarpetas con nombres similares, por lo que si desea que el marco cargue automáticamente una clase con espacio de nombres que se invoca de la siguiente manera:
$ f3 -> set ( ' AUTOLOAD ' , ' autoload/ ' );
$ obj = new Gadgets iPad ;
Puede crear una jerarquía de carpetas que siga la misma estructura. Suponiendo que /var/www/html/
es su raíz web, F3 buscará la clase en /var/www/html/autoload/gadgets/ipad.php
. El archivo ipad.php
debe tener el siguiente código mínimo:-
namespace Gadgets ;
class iPad {}
Recuerde: todos los nombres de directorios en Fat-Free deben terminar con una barra. Puede asignar una ruta de búsqueda para el cargador automático de la siguiente manera:-
$ f3 -> set ( ' AUTOLOAD ' , ' main/;aux/ ' );
F3, al ser un marco compatible con espacios de nombres, le permite utilizar un método en una clase con espacio de nombres como controlador de ruta, y hay varias formas de hacerlo. Para llamar a un método estático: -
$ f3 -> set ( ' AUTOLOAD ' , ' classes/ ' );
$ f3 -> route ( ' GET|POST / ' , ' MainHome::show ' );
El código anterior invocará el método show()
estático de la clase Home
dentro del espacio de nombres Main
. La clase Home
debe guardarse en la carpeta classes/main/home.php
para que se cargue automáticamente.
Si prefieres trabajar con objetos:-
$ f3 -> route ( ' GET|POST / ' , ' MainHome->show ' );
creará una instancia de la clase Home
en tiempo de ejecución y llamará al método show()
a partir de entonces.
F3 tiene un par de detectores de eventos de enrutamiento que pueden ayudarlo a mejorar el flujo y la estructura de las clases de controlador. Digamos que tiene una ruta definida de la siguiente manera: -
$ f3 -> route ( ' GET / ' , ' Main->home ' );
Si la aplicación recibe una solicitud HTTP que coincide con la ruta anterior, F3 crea una instancia Main
, pero antes de ejecutar el método home()
, el marco busca un método en esta clase llamado beforeRoute()
. En caso de que se encuentre, F3 ejecuta el código contenido en el controlador de eventos beforeRoute()
antes de transferir el control al método home()
. Una vez logrado esto, el marco busca un controlador de eventos afterRoute()
. Al igual que beforeRoute()
, el método se ejecuta si está definido.
Aquí hay otra ventaja de F3: -
$ f3 -> route ( ' GET /products/@action ' , ' Products->@action ' );
Si su aplicación recibe una solicitud de, digamos, /products/itemize
, F3 extraerá la cadena 'itemize'
de la URL y la pasará al token @action
en el controlador de ruta. Luego, F3 buscará una clase llamada Products
y ejecutará el método itemize()
.
Los manejadores de rutas dinámicas pueden tener varias formas: -
// static method
$ f3 -> route ( ' GET /public/@genre ' , ' Main::@genre ' );
// object mode
$ f3 -> route ( ' GET /public/@controller/@action ' , ' @controller->@action ' );
F3 desencadena un error HTTP 404 Not Found
en tiempo de ejecución si no puede transferir el control a la clase o método asociado con la ruta actual, es decir, una clase o método no definido.
Los patrones de enrutamiento pueden contener modificadores que indican al marco que base su decisión de enrutamiento en el tipo de solicitud HTTP:
$ f3 -> route ( ' GET /example [ajax] ' , ' Page->getFragment ' );
$ f3 -> route ( ' GET /example [sync] ' , ' Page->getFull ' );
La primera declaración enrutará la solicitud HTTP a la devolución de llamada Page->getFragment()
solo si el servidor recibe un encabezado X-Requested-With: XMLHttpRequest
(objeto AJAX). Si se detecta una solicitud ordinaria (síncrona), F3 simplemente bajará al siguiente patrón coincidente y, en este caso, ejecuta la devolución de llamada Page->getFull()
.
Si no se definen modificadores en un patrón de enrutamiento, tanto los tipos de solicitud AJAX como síncronos se enrutan al controlador especificado.
Los modificadores de patrón de ruta también son reconocidos por $f3->map()
.
Las variables definidas en Fat-Free son globales, es decir, cualquier componente MVC puede acceder a ellas. Los globales de framework no son idénticos a los globales de PHP. Una variable F3 llamada content
no es idéntica a $content
de PHP. F3 es un lenguaje de dominio específico por derecho propio y mantiene su propia tabla de símbolos separada para las variables del sistema y de la aplicación. El marco, como todo programa orientado a objetos bien diseñado, no contamina el espacio de nombres global de PHP con constantes, variables, funciones o clases que puedan entrar en conflicto con cualquier aplicación. A diferencia de otros marcos, F3 no utiliza la declaración define()
de PHP. Todas las constantes del marco se limitan a clases.
Para asignar un valor a una variable sin grasa:
$ 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: Las variables Fat-Free aceptan todos los tipos de datos PHP, incluidos objetos y funciones anónimas.
Para configurar varias variables a la vez:
$ f3 -> mset (
[
' foo ' => ' bar ' ,
' baz ' => 123
]
);
Para recuperar el valor de una variable de marco llamada var
: -
echo $ f3 -> get ( ' var ' ); // or
echo $ f3 -> var ;
Para eliminar una variable sin grasa de la memoria si ya no la necesita (deséchela para que no interfiera con sus otras funciones/métodos), use el método:-
$ f3 -> clear ( ' var ' ); // or
unset( $ f3 -> var );
Para saber si una variable ha sido definida previamente:-
$ f3 -> exists ( ' var ' ) //
isset ( $ f3 -> var )
F3 mantiene su propia tabla de símbolos para las variables del marco y de la aplicación, que son independientes de las de PHP. Algunas variables están asignadas a globales de PHP. SESSION
de Fat-Free es equivalente a $_SESSION
y REQUEST
se asigna a $_REQUEST
. Se recomienda el uso de variables de marco, en lugar de PHP, para ayudarle con la transferencia de datos entre diferentes funciones, clases y métodos. También tienen otras ventajas: -
SESSION
también cambia $_SESSION
subyacente de PHP. Alterar este último también altera la contraparte del marco. Fat-Free no mantiene simplemente un almacenamiento tonto para las variables y sus valores. También puede automatizar la gestión de sesiones y otras cosas. Asignar o recuperar un valor a través de la variable SESSION
de F3 inicia automáticamente la sesión. Si usa $_SESSION
(o funciones relacionadas con la sesión) directamente, en lugar de la variable de marco SESSION
, su aplicación se vuelve responsable de administrar las sesiones.
Como regla general, las variables del marco no persisten entre solicitudes HTTP. Sólo SESSION
y COOKIE
(y sus elementos) que están asignados a las variables globales $_SESSION
y $_COOKIE
de PHP están exentos de la naturaleza sin estado de HTTP.
Hay varias variables globales predefinidas que Fat-Free utiliza internamente y ciertamente puede utilizarlas en su aplicación. Asegúrate de saber lo que estás haciendo. La modificación de algunas variables globales de Fat-Free puede dar lugar a un comportamiento inesperado del sistema.
El marco tiene varias variables para ayudarle a mantener organizados sus archivos y estructuras de directorios. Hemos visto cómo podemos automatizar la carga de clases usando AUTOLOAD
. Hay una variable global UI
, que contiene la ruta que apunta a la ubicación de sus vistas/plantillas HTML. DEBUG
es otra variable que usará con bastante frecuencia durante el desarrollo de la aplicación y se usa para configurar la detalle de los seguimientos de errores.
Consulte la Referencia rápida si necesita una lista completa de variables de marco integradas.
Una variable de marco puede contener cualquier número de letras, dígitos y guiones bajos. Debe comenzar con un carácter alfabético y no debe tener espacios. Los nombres de las variables distinguen entre mayúsculas y minúsculas.
F3 utiliza mayúsculas para las variables globales internas predefinidas. Nada le impide utilizar nombres de variables que contengan mayúsculas en su propio programa, pero como regla general, utilice minúsculas (o camelCase) cuando configure sus propias variables para evitar cualquier posible conflicto con las versiones actuales y futuras del marco. .
No debe utilizar palabras reservadas de PHP como if
, for
, class
, default
, etc. como nombres de variables de marco. Estos pueden causar resultados impredecibles.
F3 también proporciona una serie de herramientas para ayudarle con las variables del marco.
$ 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 también proporciona algunos métodos primitivos para trabajar con variables de matriz: -
$ 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
A diferencia de otros marcos que tienen estructuras de carpetas rígidas, F3 le brinda mucha flexibilidad. Puede tener una estructura de carpetas similar a esta (las palabras entre paréntesis y en mayúsculas representan las variables del marco F3 que necesitan 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)
Siéntete libre de organizar tus archivos y directorios como quieras. Simplemente configure las variables globales F3 apropiadas. Si desea un sitio realmente seguro, Fat-Free incluso le permite almacenar todos sus archivos en un directorio al que no se puede acceder desde la Web. El único requisito es que dejes index.php
, .htaccess
y tus archivos públicos, como CSS, JavaScript, imágenes, etc. en una ruta visible para tu navegador.
Fat-Free genera sus propias páginas de error HTML, con seguimientos de pila para ayudarle con la depuración. Aquí hay un ejemplo: -
Error Interno del Servidor
strpos() espera al menos 2 parámetros, 0 dado
• var/html/dev/main.php:96 strpos() • var/html/dev/index.php:16 Base->run()
Si cree que es demasiado sencillo o desea hacer otras cosas cuando se produce el error, puede crear su propio controlador de errores 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 mantiene una variable global que contiene los detalles del último error que ocurrió en su aplicación. La variable ERROR
es una matriz estructurada de la siguiente manera: -
ERROR.code - displays the error code (404, 500, etc.)
ERROR.status - header and page title
ERROR.text - error context
ERROR.trace - stack trace
Mientras desarrolla su aplicación, es mejor establecer el nivel de depuración al máximo para que pueda rastrear todos los errores hasta su causa raíz: -
$ f3 -> set ( ' DEBUG ' , 3 );
Simplemente inserte el comando en la secuencia de arranque de su aplicación.
Una vez que su aplicación esté lista para su lanzamiento, simplemente elimine la declaración de su aplicación o reemplácela con: -
$ f3 -> set ( ' DEBUG ' , 0 );
Esto suprimirá la salida del seguimiento de la pila en cualquier página de error HTML generada por el sistema (porque no debe ser vista por los visitantes de su sitio).
DEBUG
puede tener valores que van desde 0 (rastreo de pila suprimido) a 3 (más detallado).
¡No lo olvides! Los seguimientos de pila pueden contener rutas, nombres de archivos, comandos de bases de datos, nombres de usuarios y contraseñas. Podría exponer su sitio web a riesgos de seguridad innecesarios si no establece la variable global DEBUG
en 0 en un entorno de producción.
Si su aplicación necesita ser configurable por el usuario, F3 proporciona un método útil para leer archivos de configuración para configurar su aplicación. De esta manera, usted y sus usuarios pueden modificar la aplicación sin alterar ningún código PHP.
En lugar de crear un script PHP que contenga el siguiente código de muestra: –
$ 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 ]);
Puede crear un archivo de configuración que haga lo mismo: –
[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
En lugar de largas declaraciones $f3->set()
en su código, puede indicarle al marco que cargue un archivo de configuración como sustituto del código. Guardemos el texto anterior como setup.cfg. Luego podemos llamarlo con un simple:-
$ f3 -> config ( ' setup.cfg ' );
No es necesario citar los valores de cadena, a menos que desee incluir espacios iniciales o finales. Si una coma debe tratarse como parte de una cadena, encierre la cadena entre comillas dobles; de lo contrario, el valor se tratará como una matriz (la coma se utiliza como separador de elementos de la matriz). Las cadenas pueden abarcar varias líneas: -
[globals]
str = " this is a
very long
string "
F3 también le brinda la posibilidad de definir rutas HTTP en archivos de configuración: -
[routes]
GET /=home
GET / 404 =App->page404
GET /page/@ num =Page->@controller
Los mapas de ruta también se pueden definir en archivos de configuración: -
[maps]
/ blog =BlogLogin
/blog/@ controller =Blog@controller
Los encabezados de las secciones [globals]
, [routes]
y [maps]
son obligatorios. Puede combinar ambas secciones en un único archivo de configuración, aunque se recomienda tener [routes]
y [maps]
en un archivo separado. De esta manera, puede permitir que los usuarios finales modifiquen algunos indicadores específicos de la aplicación y, al mismo tiempo, impedirles que interfieran con su lógica de enrutamiento.
Una interfaz de usuario como una página HTML debe ser independiente del código PHP subyacente relacionado con el enrutamiento y la lógica empresarial. Esto es fundamental para el paradigma MVC. Una revisión básica como convertir <h3>
a <p>
no debería exigir un cambio en el código de su aplicación. De la misma manera, transformar una ruta simple como GET /about
a GET /about-us
no debería tener ningún efecto en su interfaz de usuario y lógica de negocios (la vista y el modelo en MVC, o la representación y el método en RMR).
Mezclar construcciones de programación y componentes de interfaz de usuario en un solo archivo, como la codificación espagueti, hace que el mantenimiento futuro de la aplicación sea una pesadilla.
F3 admite PHP como motor de plantilla. Eche un vistazo a este fragmento html guardado como template.htm
:-.
< p > Hello, < ?php echo $name; ? > ! </ p >
Si las etiquetas cortas están habilitadas en su servidor, esto también debería funcionar:-
< p > Hello, < ?= $name ? > </ p >
Para mostrar esta plantilla, puede tener un código PHP que se ve así (almacenado en un archivo separado de la plantilla):-
$ 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 ();
El único problema con el uso de PHP como motor de plantilla, debido al código PHP integrado en estos archivos, es el esfuerzo consciente necesario para cumplir con las directrices sobre la separación de las preocupaciones y resistir la tentación de mezclar la lógica comercial con su interfaz de usuario.
Como alternativa a PHP, puede usar el propio motor de plantilla de F3. El fragmento HTML anterior se puede reescribir como:-
< p > Hello, {{ @name }}! </ p >
y el código necesitaba para ver esta plantilla:-
$ 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 ();
Al igual que los tokens de enrutamiento utilizados para capturar variables en URL (todavía recuerda el ejemplo GET /brew/@count
en la sección anterior?), Los tokens de plantilla F3 comienzan con el símbolo @
seguido de una serie de letras y dígitos encerrados en aparatos ortopédicos rizados. El primer personaje debe ser alfa. Los tokens de plantilla tienen una correspondencia uno a uno con variables marco. El marco reemplaza automáticamente un token con el valor almacenado en una variable del mismo nombre.
En nuestro ejemplo, F3 reemplaza el token @name
en nuestra plantilla con el valor que asignamos a la variable de nombre. En tiempo de ejecución, la salida del código anterior será:-
< p > Hello, world </ p >
¿Preocupado por el rendimiento de las plantillas F3? En tiempo de ejecución, el marco analiza y compila/convierte una plantilla F3 en código PHP la primera vez que se muestra a través de $template->render()
. El marco luego usa este código compilado en todas las llamadas posteriores. Por lo tanto, el rendimiento debe ser el mismo que las plantillas de PHP, si no mejor debido a la optimización del código realizada por el compilador de plantillas cuando hay plantillas más complejas involucradas.
Ya sea que use el motor de plantilla de PHP o el propietario de F3, la representación de plantillas puede ser significativamente más rápida si tiene APC, Wincache o Xcache disponible en su servidor.
Como se mencionó anteriormente, las variables de marco pueden contener cualquier tipo de datos de PHP. Sin embargo, el uso de los tipos de datos no escalares en plantillas F3 puede producir resultados extraños si no tiene cuidado. Las expresiones en los aparatos ortopédicos siempre se evaluarán y se convertirán en cadena. Debe limitar las variables de su interfaz de usuario a escalares simples:- Tipos de datos string
, integer
, boolean
o float
.
¿Pero qué pasa con las matrices? Sin grasa reconoce las matrices y puede emplearlas en sus plantillas. Puedes tener algo como:-
< p > {{ @buddy[0] }}, {{ @buddy[1] }}, and {{ @buddy[2] }} </ p >
Y llenue la matriz @buddy
en su código PHP antes de servir la plantilla:-
$ f3 -> set ( ' buddy ' ,[ ' Tom ' , ' Dick ' , ' Harry ' ]);
Sin embargo, si simplemente inserta {{ @buddy }}
en su plantilla, PHP lo reemplazará con 'Array'
porque convierte el token en una cadena. PHP, por otro lado, generará un aviso Array to string conversion
en tiempo de ejecución.
F3 le permite incrustar expresiones en plantillas. Estas expresiones pueden adoptar varias formas, como cálculos aritméticos, expresiones booleanas, constantes de PHP, etc. Aquí hay algunos ejemplos:--
{{ 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 }}
Una nota adicional sobre las expresiones de matriz: tenga en cuenta que @foo.@bar
es una concatenación de cadena $foo.$bar
), mientras que @foo.bar
se traduce en $foo['bar']
. Si $foo[$bar]
es lo que pretendía, use la notación regular @foo[@bar]
.
Las variables de marco también pueden contener funciones anónimas:
$ f3 -> set ( ' func ' ,
function ( $ a , $ b ) {
return $ a . ' , ' . $ b ;
}
);
El motor de plantilla F3 interpretará el token como se esperaba, si especifica la siguiente expresión:
{{ @func('hello','world') }}
La sustitución de variable simple es una cosa que todos los motores de plantilla tienen. Sin grasa tiene más de sus mangas:-
< include href =" header.htm " />
La Directiva incrustará el contenido de la plantilla de encabezado.htm en la posición exacta donde se indica la directiva. También puede tener contenido dinámico en forma de:-
< include href =" {{ @content }} " />
Un uso práctico para dicha directiva de plantilla es cuando tiene varias páginas con un diseño HTML común pero con contenido diferente. Instruir el marco para insertar una subplaz en su plantilla principal es tan simple como escribir el siguiente 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 ' );
Una subplaz puede contener cualquier número de directivas. F3 permite plantillas anidadas ilimitadas.
Puede especificar los nombres de archivo con algo más que .htm o .html extensiones de archivo, pero es más fácil verlos previamente en su navegador web durante la fase de desarrollo y depuración. El motor de plantilla no se limita a la representación de archivos HTML. De hecho, puede usar el motor de plantilla para representar otros tipos de archivos.
La directiva <include>
también tiene un atributo if
opcional para que pueda especificar una condición que debe satisfacerse antes de insertar la subplaz:--
< include if =" {{ count(@items) }} " href =" items.htm " />
Durante el curso de la escritura/depuración de los programas con F3 y las plantillas de diseño, puede haber casos en las que se puede deshabilitar la visualización de un bloque de HTML puede ser útil. Puede usar la directiva <exclude>
para este propósito:-
< exclude >
< p > A chunk of HTML we don't want displayed at the moment </ p >
</ exclude >
Eso es como la etiqueta de comentarios <!-- comment -->
html, pero la directiva <exclude>
hace que el bloque HTML sea totalmente invisible una vez que se representa la plantilla.
Aquí hay otra forma de excluir el contenido de la plantilla o agregar comentarios:-
{* < p > A chunk of HTML we don't want displayed at the moment </ p > *}
Otra característica de plantilla útil es la directiva <check>
. Le permite incrustar un fragmento HTML dependiendo de la evaluación de una determinada condición. Aquí hay algunos ejemplos:-
< 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 >
Puede tener tantas directivas anidadas <check>
como necesite.
Una expresión de F3 dentro de un atributo IF que equivale a NULL
, una cadena vacía, una FALSE
booleana, una matriz vacía o cero, invoca automáticamente <false>
. Si su plantilla no tiene un bloque <false>
, entonces las etiquetas de apertura y cierre <true>
son opcionales:-
< check if =" {{ @loggedin }} " >
< p > HTML chunk to be included if condition is true </ p >
</ check >
Sin grasa también puede manejar bloques HTML repetitivos:-
< repeat group =" {{ @fruits }} " value =" {{ @fruit }} " >
< p > {{ trim(@fruit) }} </ p >
</ repeat >
El atributo group
@fruits
dentro de la directiva <repeat>
debe ser una matriz y debe establecerse en su código PHP en consecuencia:-
$ f3 -> set ( ' fruits ' ,[ ' apple ' , ' orange ' , ' banana ' ]);
No se obtiene nada asignando un valor a @fruit
en su código de aplicación. Sin grasa ignora cualquier valor preestablecido que pueda tener porque utiliza la variable para representar el elemento actual durante la iteración sobre el grupo. La salida del fragmento de plantilla HTML anterior y el código PHP correspondiente se convierte en:-
< p > apple </ p >
< p > orange </ p >
< p > banana </ p >
El marco permite anidación ilimitada de bloques <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 el siguiente comando F3:-
$ f3 -> set ( ' div ' ,
[
' coffee ' =>[ ' arabica ' , ' barako ' , ' liberica ' , ' kopiluwak ' ],
' tea ' =>[ ' darjeeling ' , ' pekoe ' , ' samovar ' ]
]
);
Como resultado, obtienes el siguiente 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 >
Increíble, ¿no? Y lo único que tenía que hacer en PHP era definir el contenido de una sola variable F3 div
para reemplazar el token @div
. Sin grasa hace que tanto la programación como el diseño de plantillas web sean realmente fáciles.
El atributo value
de la Directiva de plantilla <repeat>
devuelve el valor del elemento actual en la iteración. Si necesita obtener la clave de matriz del elemento actual, use el atributo key
en su lugar. El atributo key
es opcional.
<repeat>
también tiene un atributo de contador opcional que se puede usar de la siguiente manera:-
< repeat group =" {{ @fruits }} " value =" {{ @fruit }} " counter =" {{ @ctr }} " >
< p class =" {{ @ctr%2?'odd':'even' }} " > {{ trim(@fruit) }} </ p >
</ repeat >
Internamente, el motor de plantilla de F3 registra el número de iteraciones de bucle y ahorra ese valor en la variable/token @ctr
, que se usa en nuestro ejemplo para determinar la clasificación impar/par.
Si tiene que insertar tokens F3 dentro de una sección <script>
o <style>
de su plantilla, el marco aún las reemplazará de la manera habitual:--
< script type =" text/javascript " >
function notify ( ) {
alert ( 'You are logged in as: {{ @userID }}' ) ;
}
</ script >
Directivas de plantilla de incrustación dentro de sus etiquetas <script>
o <style>
no requiere un manejo 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 defecto, Fat-Free usa el conjunto de caracteres UTF-8 a menos que se cambie. Puede anular este comportamiento emitiendo algo como:-
$ f3 -> set ( ' ENCODING ' , ' ISO-8859-1 ' );
Una vez que informe el marco del conjunto de caracteres deseado, F3 lo usará en todas las plantillas HTML y XML hasta que se altere nuevamente.
Como se mencionó anteriormente en esta sección, el marco no se limita a las plantillas HTML. Puede procesar plantillas XML igual de bien. La mecánica es bastante similar. Todavía tiene lo mismo {{ @variable }}
y {{ expression }}
Tokens, <repeat>
, <check>
, <include>
, Y <exclude>
DIRECTIVAS A TU ELIMINACIÓN. Solo dígale a F3 que está pasando un archivo XML en lugar de HTML:-
echo Template:: instance ()-> render ( ' template.xml ' , ' application/xml ' );
El segundo argumento representa el tipo MIME del documento que se presenta.
El componente de vista de MVC cubre todo lo que no se encuentra en el modelo y el controlador, lo que significa que su presentación puede y debe incluir todo tipo de interfaces de usuario, como RSS, correo electrónico, RDF, FOAF, archivos de texto, etc. El ejemplo A continuación, muestra cómo separar su presentación de correo electrónico de la lógica comercial de su aplicación:-
MIME-Version: 1.0
Content-type: text/html; charset={{ @ENCODING }}
From: {{ @from }}
To: {{ @to }}
Subject: {{ @subject }}
< p > Welcome, and thanks for joining {{ @site }}! </ p >
Guarde la plantilla de correo electrónico anterior como bienvenida.txt. El código F3 asociado sería:-
$ 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 ' )
);
Consejo: Reemplace la función SMTP Mail () con IMAP_MAIL () si su script se comunica con un servidor IMAP.
¿Ahora no es eso algo? Por supuesto, si tiene un paquete de destinatarios de correo electrónico, utilizaría una base de datos para completar el primer nombre, el nombre de último nombre y los tokens de correo electrónico.
Aquí hay una solución alternativa utilizando el complemento SMTP del 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 admite múltiples idiomas de la caja.
Primero, cree un archivo de diccionario con la siguiente estructura (un archivo por idioma):-
<?php
return [
' love ' => ' I love F3 ' ,
' today ' => ' Today is {0,date} ' ,
' pi ' => ' {0,number} ' ,
' money ' => ' Amount remaining: {0,number,currency} '
];
Guárdelo como dict/en.php
. Creemos otro diccionario, esta vez para alemán. Guarde el archivo como dict/de.php
:-
<?php
return [
' love ' => ' Ich liebe F3 ' ,
' today ' => ' Heute ist {0,date} ' ,
' money ' => ' Restbetrag: {0,number,currency} '
];
Los diccionarios no son más que pares de valor clave. F3 instancias automáticamente a las variables de marco basadas en las claves en los archivos de idioma. Como tal, es fácil insertar estas variables como tokens en sus plantillas. Usando el motor de plantilla F3:-
< h1 > {{ @love }} </ h1 >
< p >
{{ @today,time() | format }}. < br />
{{ @money,365.25 | format }} < br />
{{ @pi }}
</ p >
Y la versión más larga que utiliza PHP como motor de plantilla:-
<?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>
A continuación, instruimos a F3 que busque diccionarios en el dict/
carpeta:-
$ f3 -> set ( ' LOCALES ' , ' dict/ ' );
Pero, ¿cómo determina el marco qué idioma usar? F3 lo detectará automáticamente mirando primero los encabezados de solicitud HTTP, específicamente el encabezado Accept-Language
enviado por el navegador.
Para anular este comportamiento, puede activar F3 para usar un idioma especificado por el usuario o la aplicación:-
$ f3 -> set ( ' LANGUAGE ' , ' de ' );
Nota: En el ejemplo anterior, la clave PI existe solo en el diccionario inglés. El marco siempre usará inglés ( en
) como un respaldo para llenar las claves que no están presentes en el idioma especificado (o detectado).
También puede crear archivos de diccionario para variantes de idioma como en-US
, es-AR
, etc. En este caso, F3 usará primero la variante de idioma (como es-AR
). Si hay claves que no existen en la variante, el marco buscará la clave en el lenguaje raíz ( es
), luego use el archivo en
del idioma como el retroceso final. Los pares de valor clave del diccionario se convierten en variables F3 una vez referenciadas. Asegúrese de que las claves no entren en conflicto con ninguna variable de marco instanciada a través de $f3->set()
, $f3->mset()
o $f3->config()
.
¿Notó que el peculiar 'Today is {0,date}'
en nuestro ejemplo anterior? La capacidad multilingüe de F3 depende de las reglas de formato de cadena/mensaje del proyecto de la UCI. El marco utiliza su propio subconjunto de la implementación de formato de cadena de la ICU. No hay necesidad de que la extensión intl
de PHP se active en el servidor.
Una cosa más: F3 también puede cargar archivos formateados de estilo .ini como diccionarios:-
love = " I love F3 "
today = " Today is {0,date} "
pi = " {0,number} "
money = " Amount remaining: {0,number,currency} "
Guárdelo como dict/en.ini
para que el marco pueda cargarlo automáticamente.
De manera predeterminada, tanto el manejador de la vista como el motor de plantilla escapan todas las variables renderizadas, es decir, convertidas en entidades HTML para protegerlo de posibles ataques de inyección de XSS e inyección de código. Por otro lado, si desea aprobar fragmentos HTML válidos de su código de aplicación a su plantilla:-
$ f3 -> set ( ' ESCAPE ' , FALSE );
Esto puede tener efectos indeseables. Es posible que no desee que todas las variables pasen a través de un rescate. Sin grasa le permite un augar las variables individualmente. Para plantillas F3:-
{{ @html_content | raw }}
En el caso de las plantillas de PHP:-
<?php echo View:: instance ()-> raw ( $ html_content ); ?>
Como adición al envío automático de las variables F3, el marco también le brinda una mano libre para desinfectar la entrada del usuario de los formularios HTML:--
$ f3 -> scrub ( $ _GET , ' p; br; span; div; a ' );
Este comando eliminará todas las etiquetas (excepto las especificadas en el segundo argumento) y los caracteres inseguros de la variable especificada. Si la variable contiene una matriz, cada elemento en la matriz se desinfecta de manera recursiva. Si se pasa un asterisco (*) como el segundo argumento, $f3->scrub()
permite que todas las etiquetas HTML pasen a través de los caracteres de control inseguros.
La grasa está diseñada para hacer que el trabajo de interactuar con las bases de datos SQL sea muy fácil. Si no es del tipo que se sumerja en detalles sobre SQL, pero se inclina más hacia el manejo de datos orientado a objetos, puede ir directamente a la siguiente sección de este tutorial. Sin embargo, si necesita hacer algunas tareas complejas de manejo de datos y optimización de rendimiento de la base de datos, SQL es el camino a seguir.
Establecer la comunicación con un motor SQL como MySQL, SQLite, SQL Server, Sybase y Oracle se realiza utilizando el comando familiar $f3->set()
. Conectarse a una base de datos SQLite sería:-
$ db = new DB SQL ( ' sqlite:/absolute/path/to/your/database.sqlite ' );
Otro ejemplo, esta vez con MySQL:-
$ db = new DB SQL (
' mysql:host=localhost;port=3306;dbname=mysqldb ' ,
' admin ' ,
' p455w0rD '
);
DE ACUERDO. Eso fue fácil, ¿no? Así es como harías lo mismo en PHP ordinario. Solo necesita conocer el formato DSN de la base de datos a la que está conectando. Vea la sección PDO del manual de PHP.
Continuemos con nuestro código PHP:-
$ f3 -> set ( ' result ' , $ db -> exec ( ' SELECT brandName FROM wherever ' ));
echo Template:: instance ()-> render ( ' abc.htm ' );
Huh, ¿qué está pasando aquí? ¿No deberíamos configurar cosas como PDO, declaraciones, cursores, etc.? La respuesta simple es: no tienes que hacerlo. F3 simplifica todo al cuidar todo el trabajo duro en el backend.
Esta vez creamos una plantilla HTML como abc.htm
que tiene como mínimo lo siguiente:-
< repeat group =" {{ @result }} " value =" {{ @item }} " >
< span > {{ @item.brandName }} </ span >
</ repeat >
En la mayoría de los casos, el conjunto de comandos SQL debe ser suficiente para generar un resultado listo para la web para que pueda usar la variable de matriz result
en su plantilla directamente. Sea como fuere, sin grasa no le impedirá entrar en su controlador interno SQL. De hecho, la clase DBSQL
de F3 se deriva directamente de la clase PDO
de PHP, por lo que aún tiene acceso a los componentes y primitivos PDO subyacentes involucrados en cada proceso, si necesita un control de grano fino.
Aquí hay otro ejemplo. En lugar de una sola declaración proporcionada como un argumento al comando $db->exec()
, también puede aprobar una matriz de declaraciones SQL:-
$ db -> exec (
[
' DELETE FROM diet WHERE food="cola" ' ,
' INSERT INTO diet (food) VALUES ("carrot") ' ,
' SELECT * FROM diet '
]
);
F3 es lo suficientemente inteligente como para saber que si está pasando una variedad de instrucciones SQL, esto indica una transacción de lotes SQL. No tiene que preocuparse por las reversiones de SQL y los compromisos porque el marco volverá automáticamente al estado inicial de la base de datos si se produce algún error durante la transacción. Si tiene éxito, F3 comete todos los cambios realizados en la base de datos.
También puede iniciar y finalizar una transacción programáticamente:-
$ 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 ();
Se producirá una reversión si alguna de las declaraciones encuentra un error.
Para obtener una lista de todas las instrucciones de base de datos emitidas:-
echo $ db -> log ();
Pasar argumentos de cadena a las declaraciones SQL está llena de peligro. Considere esto:-
$ db -> exec (
' SELECT * FROM users ' .
' WHERE username=" ' . $ f3 -> get ( ' POST.userID ' . ' " ' )
);
Si la variable userID
POST
no pasa por ningún proceso de saneamiento de datos, un usuario malicioso puede pasar la siguiente cadena y dañar su base de datos de manera irreversible:--
admin " ; DELETE FROM users; SELECT " 1
Afortunadamente, las consultas parametrizadas lo ayudan a mitigar estos riesgos:-
$ db -> exec (
' SELECT * FROM users WHERE userID=? ' ,
$ f3 -> get ( ' POST.userID ' )
);
Si F3 detecta que el valor del parámetro de consulta/token es una cadena, la capa de acceso de datos subyacente escapa de la cadena y agrega citas según sea necesario.
Nuestro ejemplo en la sección anterior será mucho más segura de la inyección SQL si se escribe de esta manera:-
$ db -> exec (
[
' DELETE FROM diet WHERE food=:name ' ,
' INSERT INTO diet (food) VALUES (?) ' ,
' SELECT * FROM diet '
],
[
array ( ' :name ' => ' cola ' ),
array ( 1 => ' carrot ' ),
NULL
]
);
F3 está lleno de mapeadores de objetos (ORM) fáciles de usar que se sientan entre su aplicación y sus datos, lo que hace que sea mucho más fácil y rápido para usted escribir programas que manejen las operaciones de datos comunes, como crear, recuperar, actualizar, y eliminar la información (crud) de las bases de datos SQL y NoSQL. Los mapeadores de datos realizan la mayor parte del trabajo mapeando las interacciones del objeto PHP con las consultas de backend correspondientes.
Supongamos que tiene una base de datos MySQL existente que contiene una tabla de usuarios de su aplicación. (SQLITE, PostgreSQL, SQL Server, Sybase hará igual de bien). Se habría creado utilizando el siguiente comando SQL:--
CREATE TABLE users (
userID VARCHAR ( 30 ),
password VARCHAR ( 30 ),
visits INT ,
PRIMARY KEY (userID)
);
Nota: MongoDB es un motor de base de datos NoSQL e inherentemente sin esquema. F3 tiene su propia implementación de NoSQL rápida y ligera llamada JIG, que utiliza archivos planos serializados por PHP o codificados JSON. Estas capas de abstracción no requieren estructuras de datos rígidas. Los campos pueden variar de un récord a otro. También se pueden definir o dejar caer sobre la marcha.
Ahora de vuelta a SQL. Primero, establecemos la comunicación con nuestra base de datos.
$ db = new DB SQL (
' mysql:host=localhost;port=3306;dbname=mysqldb ' ,
' admin ' ,
' wh4t3v3r '
);
Para recuperar un registro de nuestra tabla:-
$ user = new DB SQL Mapper ( $ db , ' users ' );
$ user -> load ([ ' userID=? ' , ' tarzan ' ]);
La primera línea instancia un objeto de mapeador de datos que interactúa con la tabla users
en nuestra base de datos. Detrás de la escena, F3 recupera la estructura de la tabla de users
y determina qué campo (s) se definen como la (s) clave (s) primaria (s). En este punto, el objeto Mapper aún no contiene datos (estado seco), por lo que $user
no es más que un objeto estructurado, pero contiene los métodos que necesita para realizar las operaciones básicas de CRUD y algunos extras. Para recuperar un registro de nuestra tabla de usuarios con un campo userID
que contiene el valor de cadena tarzan
, usamos el load() method
. Este proceso se denomina "hidratación automática" el objeto Mapper de datos.
Fácil, ¿no? F3 entiende que una tabla SQL ya tiene una definición estructural existente dentro del motor de la base de datos. A diferencia de otros marcos, F3 no requiere declaraciones de clase adicionales (a menos que desee extender los mapeadores de datos para que se ajusten a objetos complejos), no hay asignaciones redundantes de propiedad/objeto PHP de propiedad a campo (duplicación de esfuerzos), ningún código de código (que requieren código Regeneración Si la estructura de la base de datos cambia), no hay estúpidos archivos XML/YAML para configurar sus modelos, sin comandos superfluos solo para recuperar un solo registro. Con F3, un cambio de tamaño simple de un campo varchar
en MySQL no exige un cambio en su código de aplicación. De acuerdo con MVC y "separación de preocupaciones", el administrador de la base de datos tiene tanto control sobre los datos (y las estructuras) como un diseñador de plantillas tiene sobre plantillas HTML/XML.
Si prefiere trabajar con bases de datos NoSQL, las similitudes en la sintaxis de consulta son superficiales. En el caso del mapeador de datos MongoDB, el código equivalente sería:-
$ db = new DB Mongo ( ' mongodb://localhost:27017 ' , ' testdb ' );
$ user = new DB Mongo Mapper ( $ db , ' users ' );
$ user -> load ([ ' userID ' => ' tarzan ' ]);
Con la plantilla, la sintaxis es similar al motor de plantilla de F3:-
$ db = new DB Jig ( ' db/data/ ' , DB Jig:: FORMAT_JSON );
$ user = new DB Jig Mapper ( $ db , ' users ' );
$ user -> load ([ ' @userID=? ' , ' tarzan ' ]);
El marco asigna automáticamente las visits
de campo en nuestra tabla a una propiedad de mapeador de datos durante la instancia de objetos, es decir, $user=new DBSQLMapper($db,'users');
. Una vez que se crea el objeto, $user->password
y $user->userID
se asignarían a los campos password
y userID
en nuestra tabla, respectivamente.
No puede agregar o eliminar un campo asignado, o cambiar la estructura de una tabla usando el ORM. Debe hacer esto en MySQL, o cualquier motor de base de datos que esté utilizando. Después de realizar los cambios en el motor de su base de datos, sin grasa sincronizará automáticamente la nueva estructura de la tabla con su objeto Mapper de datos cuando ejecute su aplicación.
F3 deriva la estructura del mapeador de datos directamente del esquema de la base de datos. No hay conjeturas involucradas. Entiende las diferencias entre los motores de base de datos MySQL, SQLite, MSSQL, SYBASE y PostgreSQL.
Los identificadores de SQL no deben usar palabras reservadas, y deben limitarse a los caracteres alfanuméricos AZ
, 0-9
, y el símbolo de subrayamiento ( _
). Los nombres de columnas que contienen espacios (o caracteres especiales) y rodeados de citas en la definición de datos no son compatibles con el ORM. No pueden representarse correctamente como propiedades del objeto PHP.
Supongamos que queremos incrementar el número de visitas del usuario y actualizar el registro correspondiente en la tabla de nuestros usuarios, podemos agregar el siguiente código:--
$ user -> visits ++;
$ user -> save ();
Si queríamos insertar un registro, seguimos este proceso:-
$ 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 ();
Todavía usamos el mismo método save()
. Pero, ¿cómo sabe F3 cuándo se debe insertar o actualizar un registro? En el momento en que un objeto mapeador de datos se hidrata automáticamente mediante una recuperación de registro, el marco realiza un seguimiento de las claves primarias del registro (o _id
, en el caso de MongoDB y Jig), por lo que sabe qué registro debe actualizarse o eliminarse, incluso Cuando se cambian los valores de las claves primarias. Un mapeador de datos hidratado programáticamente, cuyos valores no se recuperaron de la base de datos, pero pobladas por la aplicación, no tendrán ningún recuerdo de valores anteriores en sus claves primarias. Lo mismo se aplica a MongoDB y JIG, pero usando el objeto _id
como referencia. Entonces, cuando instanciamos el objeto $user
anterior y poblamos sus propiedades con valores de nuestro programa, sin recuperar en absoluto un registro de la tabla de usuario, F3 sabe que debería insertar este registro.
Un objeto mapeador no estará vacío después de un save()
. Si desea agregar un nuevo registro a su base de datos, primero debe deshidratar el mapeador:-
$ user -> reset ();
$ user -> userID = ' cheetah ' ;
$ user -> password = password_hash ( ' unknown ' , PASSWORD_BCRYPT , [ ' cost ' => 12 ]);
$ user -> save ();
Llamar save()
una segunda vez sin invocar reset()
simplemente actualizará el registro que actualmente apunta por el mapeador.
Aunque el problema de tener claves primarias en todas las tablas en su base de datos es argumentativa, F3 no le impide crear un objeto de mapeador de datos que se comunique con una tabla que no contiene claves primarias. El único inconveniente es: no puede eliminar o actualizar un registro asignado porque no hay absolutamente ninguna manera para que F3 determine a qué registro se refiere más el hecho de que las referencias posicionales no son confiables. Las ID de fila no son portátiles en diferentes motores SQL y el controlador de la base de datos PHP no puede devolverse.
Para eliminar un registro asignado de nuestra tabla, invoque el método erase()
en un mapeador de datos auto-hidratado. Por ejemplo:-
$ user = new DB SQL Mapper ( $ db , ' users ' );
$ user -> load ([ ' userID=? AND password=? ' , ' cheetah ' , ' ch1mp ' ]);
$ user -> erase ();
La sintaxis de la consulta de la Jig sería ligeramente similar:-
$ user = new DB Jig Mapper ( $ db , ' users ' );
$ user -> load ([ ' @userID=? AND @password=? ' , ' cheetah ' , ' chimp ' ]);
$ user -> erase ();
Y el equivalente de MongoDB sería:-
$ user = new DB Mongo Mapper ( $ db , ' users ' );
$ user -> load ([ ' userID ' => ' cheetah ' , ' password ' => ' chimp ' ]);
$ user -> erase ();
Para averiguar si nuestro mapeador de datos fue hidratado o no:-
if ( $ user -> dry ())
echo ' No record matching criteria ' ;
Hemos cubierto los manejadores de crud. Hay algunos métodos adicionales que puede encontrar útiles:-
$ f3 -> set ( ' user ' , new DB SQL Mapper ( $ db , ' users ' ));
$ f3 -> get ( ' user ' )-> copyFrom ( ' POST ' );
$ f3 -> get ( ' user ' )-> save ();
Observe que también podemos usar variables sin grasa como contenedores para objetos mapeadores. El método copyFrom()
hidrata el objeto Mapper con elementos de una variable de matriz de marco, cuyas teclas de matriz deben tener nombres idénticos a las propiedades del objeto mapper, que a su vez corresponden a los nombres de campo del registro. Por lo tanto, cuando se envía un formulario web (suponiendo que el atributo de nombre HTML esté configurado en userID
), el contenido de ese campo de entrada se transfiere a $_POST['userID']
, duplicado por F3 en su variable POST.userID
, y se guarda a El campo asignado $user->userID
en la base de datos. El proceso se vuelve muy simple si todos tienen elementos de nombre idénticos. Consistencia en las teclas de matriz, nombres de token de plantilla, es decir, nombres de variables de marco y nombres de campo es clave :)
Por otro lado, si queríamos recuperar un registro y copiar los valores de campo a una variable marco para su uso posterior, como la representación de plantillas:--
$ f3 -> set ( ' user ' , new DB SQL Mapper ( $ db , ' users ' ));
$ f3 -> get ( ' user ' )-> load ([ ' userID=? ' , ' jane ' ]);
$ f3 -> get ( ' user ' )-> copyTo ( ' POST ' );
Luego podemos asignar {{ @post.userid}} al atributo de valor del mismo campo de entrada. En resumen, el campo de entrada HTML se verá así:-
< input type =" text " name =" userID " value =" {{ @POST.userID }} " />
Los métodos save()
, update()
, copyFrom()
Data Mapper y las variantes parametrizadas de load()
y erase()
están a salvo de la inyección SQL.
De manera predeterminada, el método load()
de Data Mapper recupera solo el primer registro que coincide con los criterios especificados. Si tiene más de uno que cumple con la misma condición que el primer registro cargado, puede usar el método skip()
para la navegación:-
$ 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 );
Puede usar $user->next()
como sustituto de $user->skip()
, y $user->prev()
si cree que da más significado a $user->skip(-1)
.
Use el método dry()
para verificar si ha maniobrado más allá de los límites del conjunto de resultados. dry()
devolverá verdadero si intenta skip(-1)
en el primer registro. También devolverá verdadero si skip(1)
en el último registro que cumple con los criterios de recuperación.
El método load()
acepta un segundo argumento: una matriz de opciones que contienen pares de valor clave como:-
$ user -> load (
[ ' visits>? ' , 3 ],
[
' order ' => ' userID DESC '
'offset'=> 5 ,
' limit ' => 3
]
);
Si estás usando MySQL, la consulta se traduce a:-
SELECT * FROM users
WHERE visits > 3
ORDER BY userID DESC
LIMIT 3 OFFSET 5 ;
Esta es una forma de presentar datos en pequeños fragmentos. Aquí hay otra forma de paginar los resultados:-
$ page = $ user -> paginate ( 2 , 5 ,[ ' visits>? ' , 3 ]);
En el escenario anterior, F3 recuperará registros que coinciden con los criterios 'visits>3'
. Luego limitará los resultados a 5 registros (por página) a partir de la página Offset 2 (0 basada en 0). El marco devolverá una matriz que consiste en los siguientes elementos:-
[subset] array of mapper objects that match the criteria
[count] number of subsets available
[pos] actual subset position
La posición del subconjunto real devuelta será nula si el primer argumento de paginate()
es un número negativo o excede el número de subconjuntos encontrados.
Hay casos en los que necesita recuperar un valor calculado de un campo, o un valor de referencia cruzada de otra tabla. Ingrese los campos virtuales. SQL Mini-anorm le permite trabajar en datos derivados de los campos existentes.
Supongamos que tenemos la siguiente tabla definida como:-
CREATE TABLE products
productID VARCHAR ( 30 ),
description VARCHAR ( 255 ),
supplierID VARCHAR ( 30 ),
unitprice DECIMAL ( 10 , 2 ),
quantity INT ,
PRIMARY KEY (productID)
);
No existe un campo totalprice
, por lo que podemos decirle al marco que solicite desde el motor de la base de datos el producto aritmético de los dos campos:--
$ item = new DB SQL Mapper ( $ db , ' products ' );
$ item -> totalprice = ' unitprice*quantity ' ;
$ item -> load ([ ' productID=:pid ' , ' :pid ' => ' apple ' ]);
echo $ item -> totalprice ;
El fragmento de código anterior define un campo virtual llamado totalprice
que se calcula multiplicando unitprice
por la quantity
. El mapeador SQL guarda esa regla/fórmula, por lo que cuando llega el momento de recuperar el registro de la base de datos, podemos usar el campo virtual como un campo asignado regular.
Puede tener campos virtuales más complejos:-
$ item -> mostNumber = ' MAX(quantity) ' ;
$ item -> load ();
echo $ item -> mostNumber ;
Esta vez, el marco recupera el producto con la cantidad más alta (observe el método load()
no define ningún criterio, por lo que se procesarán todos los registros en la tabla). Por supuesto, el campo virtual mostNumber
aún le dará la cifra correcta si desea limitar la expresión a un grupo específico de registros que coincidan con un criterio especificado.
También puede obtener un valor de otra tabla:-
$ item -> supplierName =
' SELECT name FROM suppliers ' .
' WHERE products.supplierID=suppliers.supplierID ' ;
$ item -> load ();
echo $ item -> supplierName ;
Cada vez que carga un registro de la tabla de productos, el ORM referencia el supplerID
en la tabla de products
con el supplierID
en la tabla suppliers
.
Para destruir un campo virtual, use unset($item->totalPrice);
. La expresión isset($item->totalPrice)
devuelve verdadero si el campo Virtual totalPrice
se definió, o falso si no es lo contrario.
Recuerde que un campo virtual debe definirse antes de la recuperación de datos. El ORM no realiza el cálculo real, ni la derivación de los resultados de otra tabla. Es el motor de la base de datos el que hace todo el trabajo duro.
Si no tiene necesidad de navegación de registro por registro, puede recuperar un lote completo de registros de una sola vez:-
$ frequentUsers = $ user -> find ([ ' visits>? ' , 3 ],[ ' order ' => ' userID ' ]);
La sintaxis de la consulta de la Jig Mapper tiene un ligero parecido:-
$ frequentUsers = $ user -> find ([ ' @visits>? ' , 3 ],[ ' order ' => ' userID ' ]);
El código equivalente usando el mongoDB mapper:-
$ frequentUsers = $ user -> find ([ ' visits ' =>[ ' $gt ' => 3 ]],[ ' userID ' => 1 ]);
El método find()
busca en la tabla users
para registros que coincidan con los criterios, clasifica el resultado por userID
y devuelve el resultado como una matriz de objetos mapeadores. find('visits>3')
es diferente de load('visits>3')
. Este último se refiere al objeto $user
actual. find()
no tiene ningún efecto en skip()
.
IMPORTANTE: Declarar una condición vacía, nula o una cadena de longitud cero como el primer argumento de find()
o load()
recuperará todos los registros. Asegúrese de saber lo que está haciendo: puede exceder la memoria de PHP en tablas o colecciones grandes.
El método find()
tiene la siguiente sintaxis:-
find (
$ criteria ,
[
' group ' => ' foo ' ,
' order ' => ' foo,bar ' ,
' limit ' => 5 ,
' offset ' => 0
]
);
find () Devuelve una matriz de objetos. Cada objeto es un mapeador a un registro que coincide con los criterios especificados.
$ place = new DB SQL Mapper ( $ db , ' places ' );
$ list = $ place -> find ( ' state="New York" ' );
foreach ( $ list as $ obj )
echo $ obj -> city . ' , ' . $ obj -> country ;
Si necesita convertir un objeto mapeador a una matriz asociativa, use el método cast()
:-
$ array = $ place -> cast ();
echo $ array [ ' city ' ]. ' , ' . $ array [ ' country ' ];
Para recuperar el número de registros en una tabla que coincida con una determinada condición, use el método count()
.
if (! $ user -> count ([ ' visits>? ' , 10 ]))
echo ' We need a better ad campaign! ' ;
También hay un método select()
que es similar a find()
pero proporciona más control de grano fino sobre los campos devueltos. Tiene una sintaxis similar a SQL:-
select (
' foo, bar, MIN(baz) AS lowest ' ,
' foo > ? ' ,
[
' group ' => ' foo, bar ' ,
' order ' => ' baz ASC ' ,
' limit ' => 5 ,
' offset ' => 3
]
);
Al igual que el método find()
, select()
no altera el contenido del objeto mapeador. Solo sirve como un método de conveniencia para consultar una mesa mapeada. El valor de retorno de ambos métodos es una matriz de objetos mapeadores. El uso de dry()
para determinar si un registro fue encontrado por uno de estos métodos es inapropiado. Si ningún registro coincide con los criterios find()
o select()
, el valor de retorno es una matriz vacía.
Si alguna vez desea averiguar qué declaraciones SQL emitidas directamente por su solicitud (o indirectamente a través de objetos mapeadores) están causando cuellos de botella de rendimiento, puede hacerlo con un simple:-----
echo $ db -> log ();
F3 realiza un seguimiento de todos los comandos emitidos al controlador de base de datos SQL subyacente, así como el tiempo que tarda en cada declaración, la información correcta que necesita para ajustar el rendimiento de la aplicación.
En la mayoría de los casos, puede vivir según las comodidades dadas por los métodos de mapeadores de datos que hemos discutido hasta ahora. Si necesita el marco para hacer un trabajo de servicio pesado, puede extender el mapeador SQL declarando sus propias clases con métodos personalizados, pero no puede evitar que las manos sean grasosas en un Hardcore SQL:------
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 ();
Extender los mapeadores de datos de esta manera es una manera fácil de construir los modelos relacionados con DB de su aplicación.
Si es útil con SQL, probablemente diría: todo en el ORM se puede manejar con consultas SQL de la vieja escuela. En efecto. Podemos prescindir de los oyentes de eventos adicionales utilizando desencadenantes de la base de datos y procedimientos almacenados. Podemos realizar consultas relacionales con tablas unidas. El ORM es solo una sobrecarga innecesaria. Pero el punto es: los mapeadores de datos le brindan la funcionalidad adicional de usar objetos para representar entidades de bases de datos. Como desarrollador, puede escribir código más rápido y ser más productivo. El programa resultante será más limpio, si no más corto. Pero tendrá que sopesar los beneficios contra el compromiso en la velocidad, especialmente al manejar tiendas de datos grandes y complejas. Recuerde, todos los Orms, no importa cuán delgados sean, siempre serán solo otra capa de abstracción. Todavía tienen que pasar el trabajo a los motores SQL subyacentes.
Por diseño, los ORM de F3 no proporcionan métodos para conectarse directamente entre sí, es decir, SQL se une, porque esto abre una lata de gusanos. Hace que su aplicación sea más compleja de lo que debería ser, y existe la tendencia de los objetos a través de técnicas de recuperación ansiosas o perezosas para que estén bloqueadas e incluso sin sincron . Hay formas indirectas de hacerlo en el mapeador SQL, utilizando campos virtuales, pero tendrá que hacerlo programáticamente y con su propio riesgo.
Si está tentado a aplicar conceptos de OOP "puros" en su aplicación para representar todos sus datos (porque "todo es un objeto"), tenga en cuenta que los datos casi siempre viven más que la aplicación. Es posible que su programa ya esté desactualizado mucho antes de que los datos hayan perdido su valor. No agregue otra capa de complejidad en su programa utilizando objetos y clases entrelazados que desvíen demasiado del esquema y la estructura física de los datos.
Antes de tejer múltiples objetos en su aplicación para manipular las tablas subyacentes en su base de datos, piense en esto: crear vistas para representar relaciones y desencadenantes para definir el comportamiento de los objetos en el motor de la base de datos son más eficientes. Los motores de bases de datos relacionales están diseñados para manejar vistas, tablas y desencadenantes unidas. No son tiendas de datos tontos. Las tablas unidas en una vista aparecerán como una sola tabla, y la grasa puede mapear automáticamente una vista tan bien como una mesa normal. La replicación de las uniones como objetos relacionales en PHP es más lento en comparación con el código de máquina del motor de la base de datos, el álgebra relacional y la lógica de optimización. Además, unir tablas repetidamente en nuestra aplicación es una señal segura de que el diseño de la base de datos debe ser auditado, y las vistas consideran una parte integral de la recuperación de datos. Si una tabla referencias cruzadas de otra tabla con frecuencia, considere normalizar sus estructuras o crear una vista en su lugar. Luego cree un objeto mapeador para mapear automáticamente esa vista. Es más rápido y requiere menos esfuerzo.
Considere esta vista SQL creada dentro del motor de su base de datos:-
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 ;
Su código de aplicación se vuelve simple porque no tiene que mantener dos objetos mapeadores (uno para la tabla de proyectos y otro para los usuarios) solo para recuperar datos de dos tablas unidas:--
$ combined = new DB SQL Mapper ( $ db , ' combined ' );
$ combined -> load ([ ' project=? ' , 123 ]);
echo $ combined -> name ;
Consejo: use las herramientas para que estén diseñadas. Sin grasa ya tiene un ayudante SQL fácil de usar. Úselo si necesita un martillo más grande :) Intente buscar un equilibrio entre conveniencia y rendimiento. SQL siempre será su alternativa si está trabajando en estructuras de datos complejas y heredadas.
Los complementos no son más que clases de hojas automáticas que usan el marco incorporados para extender las características y la funcionalidad de 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 );
Así es 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 ejemplo:-
$ 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. Algo como:-
< 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
. Eso es todo lo que hay que hacer.
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. El | 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]>
¡Oye amigo! ¡Ayúdame por un par de!