Мощная, но простая в использовании микроплатформа PHP, предназначенная для быстрого создания динамичных и надежных веб-приложений!
Сжатый в один файл размером ~65 КБ, F3 (как мы его с любовью называем) дает вам прочную основу, зрелую базу кода и серьезный подход к написанию веб-приложений. Под капотом находится простой в использовании набор инструментов для веб-разработки, высокопроизводительный механизм маршрутизации и кэширования URL-адресов, встроенная подсветка кода и поддержка многоязычных приложений. Он легкий, простой в использовании и быстрый. Прежде всего, это не мешает вам.
Независимо от того, являетесь ли вы новичком или опытным PHP-программистом, F3 поможет вам быстро приступить к работе. Никаких ненужных и кропотливых процедур установки. Никакой сложной настройки не требуется. Никаких запутанных структур каталогов. Нет лучшего времени, чтобы начать разработку веб-приложений простым способом, чем прямо сейчас!
F3 поддерживает готовые базы данных как SQL, так и NoSQL: MySQL, SQLite, MSSQL/Sybase, PostgreSQL, DB2 и MongoDB. Он также поставляется с мощными объектно-реляционными преобразователями для абстракции и моделирования данных, которые столь же легки, как и сама платформа. Никакой конфигурации не требуется.
Это еще не все. F3 поставляется с другими дополнительными плагинами, расширяющими его возможности:
В отличие от других фреймворков, F3 стремится быть удобным в использовании, а не обычным.
Философия фреймворка и его подход к архитектуре программного обеспечения заключаются в минимализме структурных компонентов, избегании сложности приложения и достижении баланса между элегантностью кода, производительностью приложения и производительностью программиста.
F3 имеет стабильную архитектуру корпоративного класса. Непревзойденная производительность, удобные функции и небольшой вес. Чего еще можно желать? Чтобы получить этот пакет, просто загрузите его или посетите репозиторий fatfree-core, чтобы найти последнюю версию Edge.
Для всех пользователей композиторов:
composer create-project bcosca/fatfree
composer require bcosca/fatfree-core
Настоятельно рекомендуется опытным пользователям разрабатывать новые приложения с использованием последней версии, чтобы воспользоваться преимуществами обновленной базы кода и постоянными улучшениями.
Самое актуальное руководство пользователя и подробную документацию по API с множеством примеров кода и графическим руководством можно найти на сайте fatfreeframework.com/.
Конечно, этот удобный онлайн-справочник создан на базе F3! Он демонстрирует возможности и производительность платформы. Проверьте это сейчас. Если вы хотите прочитать его напрямую на github, вы можете найти содержимое веб-сайта по адресу github.com/F3Community/F3com-data.
Дизайнер знает, что он достиг совершенства не тогда, когда нечего добавить, а когда нечего отнять. -- Антуан де Сент-Экзюпери
Fat-Free Framework позволяет легко создавать целые веб-сайты в один миг. Обладая той же мощью и краткостью, что и современные наборы инструментов и библиотеки Javascript, F3 помогает вам писать более красивые и надежные программы PHP. Один взгляд на исходный код PHP, и любому будет легко понять, как многого можно добиться с помощью такого небольшого количества строк кода и насколько эффективны результаты.
F3 — один из наиболее документированных фреймворков. Обучение этому практически ничего не стоит. Никакого строгого набора сложных для навигации структур каталогов и навязчивых шагов программирования. Никакого набора параметров конфигурации, просто чтобы отобразить 'Hello, World'
в вашем браузере. Fat-Free дает вам большую свободу и стиль, позволяющие выполнять больше работы с легкостью и за меньшее время.
Декларативный подход F3 к программированию облегчает понимание PHP-кода как новичкам, так и экспертам. Если вы знакомы с языком программирования Ruby, вы заметите сходство между микроплатформой Fat-Free и Sinatra, поскольку обе они используют простой предметно-ориентированный язык для веб-сервисов ReSTful. Но в отличие от Sinatra и его воплощений PHP (Fitzgerald, Limonade, Glue — и это лишь некоторые из них), Fat-Free выходит за рамки простой обработки маршрутов и запросов. Представления могут быть в любой форме, например в виде обычного текста, HTML, XML или сообщения электронной почты. Фреймворк поставляется с быстрым и простым в использовании механизмом шаблонов. F3 также без проблем работает с другими механизмами шаблонов, включая Twig, Smarty и сам PHP. Модели взаимодействуют с преобразователями данных F3 и помощником SQL для более сложного взаимодействия с различными ядрами баз данных. Другие плагины еще больше расширяют базовый функционал. Это полноценный фреймворк для веб-разработки – с огромными возможностями!
Разархивируйте содержимое дистрибутива в любое место на жестком диске. По умолчанию файл платформы и дополнительные плагины расположены по пути lib/
. Организуйте структуру каталогов так, как вам хочется. Для повышения безопасности вы можете переместить папки по умолчанию в путь, недоступный через Интернет. Удалите плагины, которые вам не нужны. Вы всегда можете восстановить их позже, и F3 автоматически обнаружит их присутствие.
Важно: Если ваше приложение использует APC, Memcached, WinCache, XCache или кэш файловой системы, сначала очистите все записи кэша, прежде чем перезаписывать старую версию платформы новой.
Убедитесь, что вы используете правильную версию PHP. F3 не поддерживает версии PHP ниже 7.2. Вы будете повсюду получать синтаксические ошибки (ложные срабатывания), поскольку новые языковые конструкции и замыкания/анонимные функции не поддерживаются устаревшими версиями PHP. Чтобы это узнать, откройте консоль (оболочка bash
в GNU/Linux или cmd.exe
в Windows): –
/path/to/php -v
PHP сообщит вам, какую конкретную версию вы используете, и вы должны получить что-то похожее на это:
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
При необходимости обновите его и вернитесь сюда, если вы перешли на PHP 7.4 или более позднюю версию. Для работы Fatfree требуется как минимум PHP 7.2. Если вам нужен поставщик услуг хостинга, попробуйте одну из этих услуг:
Пора начать писать наше первое приложение: -
$ f3 = require ( ' path/to/base.php ' );
$ f3 -> route ( ' GET / ' ,
function () {
echo ' Hello, world! ' ;
}
);
$ f3 -> run ();
Добавьте base.php
в первую строку с соответствующим путем. Сохраните приведенный выше фрагмент кода как index.php
в корневой папке веб-сайта. Мы написали нашу первую веб-страницу.
Используете композитор? Затем просто запустите composer require bcosca/fatfree
, и используйте следующее:
require ' vendor/autoload.php ' ;
$ f3 = Base:: instance ();
$ f3 -> route ( ' GET / ' ,
function () {
echo ' Hello, world! ' ;
}
);
$ f3 -> run ();
Первая команда сообщает интерпретатору PHP, что вы хотите, чтобы функции и возможности платформы были доступны вашему приложению. Метод $f3->route()
сообщает Fat-Free, что веб-страница доступна по относительному URL-адресу, указанному косой чертой ( /
). Любой посетитель вашего сайта, расположенного по адресу http://www.example.com/
увидит надпись 'Hello, world!'
сообщение, поскольку URL-адрес /
эквивалентен корневой странице. Чтобы создать маршрут, который ответвляется от корневой страницы, например http://www.example.com/inside/
, вы можете определить другой маршрут с помощью простой строки GET /inside
.
Описанный выше маршрут сообщает платформе отображать страницу только тогда, когда она получает запрос URL-адреса с использованием метода HTTP GET
. Более сложные веб-сайты, содержащие формы, используют другие методы HTTP, такие как POST
, и вы также можете реализовать это как часть спецификации $f3->route()
.
Если платформа обнаружит входящий запрос на вашу веб-страницу, расположенный по корневому URL-адресу /
, она автоматически направит запрос в функцию обратного вызова, которая содержит код, необходимый для обработки запроса и отображения соответствующего HTML-материала. В этом примере мы просто отправляем строку 'Hello, world!'
в веб-браузер пользователя.
Итак, мы проложили наш первый маршрут. Но это мало что даст, кроме как сообщить F3, что существует процесс, который будет обрабатывать эту операцию, и что есть некоторый текст для отображения в веб-браузере пользователя. Если на вашем сайте много страниц, вам необходимо настроить разные маршруты для каждой группы. А пока давайте будем проще. Чтобы дать указание платформе начать ожидание запросов, мы вводим команду $f3->run()
.
Не можете запустить пример? Если у вас возникли проблемы с запуском этой простой программы на вашем сервере, возможно, вам придется немного изменить настройки веб-сервера. Взгляните на пример конфигурации Apache в следующем разделе (вместе с эквивалентами Nginx и Lighttpd).
Все еще возникают проблемы? Убедитесь, что $f3 = require('path/to/base.php');
назначение идет перед любым выводом в вашем скрипте. base.php
изменяет заголовки HTTP, поэтому любой символ, выводимый в браузер до этого присвоения, приведет к ошибкам.
Наш первый пример было не слишком сложно проглотить, не так ли? Если вам нравится немного больше вкуса в обезжиренном супе, вставьте другой маршрут перед командой $f3->run()
:
$ f3 -> route ( ' GET /about ' ,
function () {
echo ' Donations go to a local charity... us! ' ;
}
);
Вы не хотите загромождать глобальное пространство имен именами функций? Fat-Free распознает различные способы сопоставления обработчиков маршрутов с классами и методами ООП:
class WebPage {
function display () {
echo ' I cannot object to an object ' ;
}
}
$ f3 -> route ( ' GET /about ' , ' WebPage->display ' );
HTTP-запросы также могут быть перенаправлены на статические методы класса:
$ f3 -> route ( ' GET /login ' , ' Auth::login ' );
Передаваемые аргументы всегда передаются в качестве второго параметра:
$ f3 -> route ( ' GET /hello/@name ' , ' User::greet ' );
class User {
public static function greet ( $ f3 , $ args ) { // $ args is type of Array
echo " Hello " . $ args [ ' name ' ];
}
}
Если предоставленный аргумент имени будет foo (/hello/foo), будет показан следующий вывод:
Hello foo
В качестве демонстрации мощного доменно-ориентированного языка (DSL) Fat-Free вы можете указать один маршрут для обработки различных возможностей:
$ f3 -> route ( ' GET /brew/@count ' ,
function ( $ f3 ) {
echo $ f3 -> get ( ' PARAMS.count ' ). ' bottles of beer on the wall. ' ;
}
);
В этом примере показано, как мы можем указать токен @count
для представления части URL-адреса. Платформа будет обслуживать любой URL-адрес запроса, который соответствует префиксу /brew/
, например /brew/99
, /brew/98
и т. д. Это отобразит '99 bottles of beer on the wall'
и '98 bottles of beer on the wall'
, соответственно. Fat-Free также примет запрос страницы для /brew/unbreakable
. (Ожидайте, что это отобразит 'unbreakable bottles of beer on the wall'
.) Когда указан такой динамический маршрут, Fat-Free автоматически заполняет глобальную переменную массива PARAMS
значением захваченных строк в URL-адресе. Вызов $f3->get()
внутри функции обратного вызова извлекает значение переменной платформы. Вы, безусловно, можете применить этот метод в своем коде как часть презентации или бизнес-логики. Но об этом мы поговорим подробнее позже.
Обратите внимание, что Fat-Free понимает точечную запись массива. Вместо этого вы можете использовать обычную запись PARAMS['count']
в коде, который подвержен опечаткам и несбалансированным фигурным скобкам. В представлениях и шаблонах платформа допускает нотацию @PARAMS.count
, которая чем-то похожа на Javascript. (Мы рассмотрим представления и шаблоны позже.)
Вот еще один способ доступа к токенам в шаблоне запроса:
$ f3 -> route ( ' GET /brew/@count ' ,
function ( $ f3 , $ params ) {
echo $ params [ ' count ' ]. ' bottles of beer on the wall. ' ;
}
);
Вы можете использовать звездочку ( *
), чтобы принять любой URL-адрес после маршрута /brew
— если вас не волнует остальная часть пути: —
$ f3 -> route ( ' GET /brew/* ' ,
function () {
echo ' Enough beer! We always end up here. ' ;
}
);
Важный момент, который следует учитывать: вы запутаетесь в Fat-Free (и в себе), если используете GET /brew/@count
и GET /brew/*
вместе в одном приложении. Используйте то или другое. Еще одна вещь: Fat-Free рассматривает GET /brew
как отдельный и отличный от маршрута GET /brew/@count
. Каждый из них может иметь разные обработчики маршрутов.
Подождите секунду — во всех предыдущих примерах мы никогда не создавали каталог на жестком диске для хранения этих маршрутов. Короткий ответ: нам не нужно. Все маршруты F3 являются виртуальными. Они не отражают структуру папок нашего жесткого диска. Если у вас есть программы или статические файлы (изображения, CSS и т. д.), которые не используют платформу (при условии, что пути к этим файлам не конфликтуют с каким-либо маршрутом, определенным в вашем приложении), программное обеспечение вашего веб-сервера доставит их в браузер пользователя при условии, что сервер настроен правильно.
При определении маршрута вы можете присвоить ему имя. Используйте имя маршрута в своем коде и шаблонах вместо введенного URL-адреса. Затем, если вам нужно изменить свои URL-адреса, чтобы угодить повелителям маркетинга, вам нужно внести изменения только в том месте, где был определен маршрут. Имена маршрутов должны соответствовать правилам именования переменных PHP (без точек, тире и дефисов).
Назовем маршрут:-
$ f3 -> route ( ' GET @beer_list: /beer ' , ' Beer->list ' );
Имя вставляется после VERB маршрута (в данном примере GET
), которому предшествует символ @
, и отделяется от части URL-адреса двоеточием :
Вы можете вставить пробел после двоеточия, если это облегчит чтение вашего кода (как показано здесь).
Чтобы получить доступ к именованному маршруту в шаблоне, получите значение именованного маршрута в качестве ключа массива ульев ALIASES
:
< a href =" {{ @ALIASES.beer_list }} " > View beer list </ a >
Чтобы перенаправить посетителя на новый URL-адрес, вызовите именованный маршрут внутри метода reroute()
например:
// a named route is a string value
$ f3 -> reroute ( ' @beer_list ' ); // note the single quotes
Если вы используете токены в своем маршруте, F3 заменит эти токены их текущим значением. Если вы хотите изменить значение токена перед вызовом перенаправления, передайте его в качестве второго аргумента.:-
$ 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) ' );
Не забудьте использовать urlencode()
для своих аргументов, если у вас есть символы, которые не соответствуют рекомендациям RFC 1738 для правильно сформированных URL-адресов.
Последняя стабильная версия PHP имеет собственный встроенный веб-сервер. Запустите его, используя следующую конфигурацию:
php -S localhost:80 -t /var/www/
Приведенная выше команда начнет перенаправлять все запросы в корневой каталог веб-сайта /var/www
. Если получен входящий HTTP-запрос на файл или папку, PHP будет искать его в корне Интернета и в случае обнаружения отправит его в браузер. В противном случае PHP загрузит файл index.php
по умолчанию (содержащий ваш код с поддержкой F3).
Если вы используете Apache, обязательно активируйте модуль перезаписи URL-адресов (mod_rewrite) в файле apache.conf (или httpd.conf). Вам также следует создать файл .htaccess, содержащий следующее:
# 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]
Сценарий сообщает Apache, что всякий раз, когда приходит HTTP-запрос и если физический файл ( !-f
), путь ( !-d
) или символическая ссылка ( !-l
) не найдены, он должен передать управление index.php
, который содержит наш главный/фронт-контроллер, который, в свою очередь, вызывает фреймворк.
.htaccess file
содержащий указанные выше директивы Apache, всегда должен находиться в той же папке, что и index.php
.
Вам также необходимо настроить Apache, чтобы он знал физическое расположение index.php
на вашем жестком диске. Типичная конфигурация:
DocumentRoot " /var/www/html "
< Directory "/var/www/html">
Options -Indexes +FollowSymLinks +Includes
AllowOverride All
Order allow,deny
Allow from All
</ Directory >
Если вы разрабатываете несколько приложений одновременно, конфигурацией виртуального хоста легче управлять:
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 >
Каждое ServerName
( site1.com
и site2.com
в нашем примере) должно быть указано в файле /etc/hosts
. В Windows вам следует отредактировать C:/WINDOWS/system32/drivers/etc/hosts
. Для вступления в силу изменений может потребоваться перезагрузка. Затем вы можете указать в своем веб-браузере адрес http://site1.com
или http://site2.com
. Виртуальные хосты значительно упрощают развертывание ваших приложений.
Для серверов Nginx рекомендуемая конфигурация (замените ip_address:port настройками FastCGI PHP вашей среды): –
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;
}
}
Серверы Lighttpd настраиваются аналогичным образом:
$HTTP["host"] =~ "www.example.com$" {
url.rewrite-once = ( "^/(.*?)(?.+)?$"=>"/index.php/$1?$2" )
server.error-handler-404 = "/index.php"
}
Установите модуль перезаписи URL-адресов и соответствующую платформу .NET, соответствующую вашей версии Windows. Затем создайте файл с именем web.config
в корне вашего приложения со следующим содержимым:
<?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>
Итак, вернемся к кодированию. Вы можете объявить страницу устаревшей и перенаправить посетителей на другой сайт/страницу:
$ f3 -> route ( ' GET|HEAD /obsoletepage ' ,
function ( $ f3 ) {
$ f3 -> reroute ( ' /newpage ' );
}
);
Если кто-то пытается получить доступ к URL-адресу http://www.example.com/obsoletepage
с помощью запроса HTTP GET или HEAD, платформа перенаправляет пользователя на URL-адрес: http://www.example.com/newpage
как показано на рисунке приведенный выше пример. Вы также можете перенаправить пользователя на другой сайт, например $f3->reroute('http://www.anotherexample.org/');
.
Изменение маршрута может быть особенно полезно, когда вам нужно выполнить некоторые работы по обслуживанию вашего сайта. У вас может быть обработчик маршрута, который информирует ваших посетителей о том, что ваш сайт не доступен в течение короткого периода времени.
HTTP-перенаправления необходимы, но они также могут быть дорогостоящими. Насколько это возможно, воздержитесь от использования $f3->reroute()
для отправки пользователя на другую страницу того же веб-сайта, если вы можете направить поток вашего приложения, вызывая функцию или метод, обрабатывающий целевой маршрут. Однако этот подход не приведет к изменению URL-адреса в адресной строке веб-браузера пользователя. Если это не то поведение, которое вам нужно, и вам действительно нужно отправить пользователя на другую страницу, в таких случаях, как успешная отправка формы или после аутентификации пользователя, Fat-Free отправляет заголовок HTTP 302 Found
. При всех других попытках перенаправления на другую страницу или сайт платформа отправляет заголовок HTTP 301 Moved Permanently
.
Во время выполнения Fat-Free автоматически генерирует ошибку HTTP 404 всякий раз, когда видит, что входящий HTTP-запрос не соответствует ни одному из маршрутов, определенных в вашем приложении. Однако бывают случаи, когда вам нужно запустить его самостоятельно.
Возьмем, к примеру, маршрут, определенный как GET /dogs/@breed
. Логика вашего приложения может включать поиск в базе данных и попытку получить запись, соответствующую значению @breed
во входящем HTTP-запросе. Поскольку Fat-Free принимает любое значение после префикса /dogs/
из-за наличия токена @breed
, отображение сообщения HTTP 404 Not Found
программно становится необходимым, когда программа не находит совпадений в нашей базе данных. Для этого используйте следующую команду: -
$ f3 -> error ( 404 );
Архитектура Fat-Free основана на концепции, согласно которой URI HTTP представляют собой абстрактные веб-ресурсы (не ограничиваясь HTML), и каждый ресурс может переходить из одного состояния приложения в другое. По этой причине F3 не имеет никаких ограничений на структуру вашего приложения. Если вы предпочитаете использовать шаблон Модель-Представление-Контроллер, F3 может помочь вам разделить компоненты приложения на части, чтобы придерживаться этой парадигмы. С другой стороны, платформа также поддерживает шаблон «Ресурс-Метод-Представление», и его реализация более проста.
Вот пример интерфейса ReST:
class Item {
function get () {}
function post () {}
function put () {}
function delete () {}
}
$ f3 = require ( ' lib/base.php ' );
$ f3 -> map ( ' /cart/@item ' , ' Item ' );
$ f3 -> run ();
Метод $f3->map()
в Fat-Free предоставляет интерфейс ReST, сопоставляя методы HTTP в маршрутах с эквивалентными методами объекта или класса PHP. Если ваше приложение получает входящий HTTP-запрос, например GET /cart/123
, Fat-Free автоматически передаст управление методу get()
объекта или класса. С другой стороны, запрос POST /cart/123
будет перенаправлен в метод post()
класса Item
.
Примечание. Браузеры не реализуют методы HTTP PUT
и DELETE
в обычных формах HTML. Эти и другие методы ReST ( HEAD
и CONNECT
) доступны только через вызовы AJAX к серверу.
Если платформа получает HTTP-запрос на маршрут, который сопоставляется с методом, который не реализован классом (возможно, вы допустили ошибку при сопоставлении маршрута или метод еще не написан), она генерирует HTTP 405 Method Not Allowed
Ошибка HTTP 405 Method Not Allowed
.
Если клиент запрашивает HTTP OPTIONS
для ресурса URL, F3 отвечает соответствующими заголовками HTTP, которые указывают, какие методы разрешены для ресурса (HEAD, GET, PUT и т. д.). Платформа не сопоставляет запрос OPTIONS
с классом.
Fat-Free позволяет загружать классы только тогда, когда они вам нужны, поэтому они не занимают больше памяти, чем требуется конкретному сегменту вашего приложения. И вам не нужно писать длинный список операторов include
или require
только для того, чтобы загрузить классы PHP, сохраненные в разных файлах и разных местах. Фреймворк может сделать это автоматически за вас. Просто сохраните файлы (по одному классу на файл) в папке и сообщите платформе автоматически загружать соответствующий файл после вызова метода в классе:
$ f3 -> set ( ' AUTOLOAD ' , ' autoload/ ' );
Вы можете назначить другое местоположение для автоматически загружаемых классов, изменив значение глобальной переменной AUTOLOAD
. Вы также можете иметь несколько путей автозагрузки. Если ваши классы организованы и расположены в разных папках, вы можете указать платформе автоматически загружать соответствующий класс при вызове статического метода или при создании экземпляра объекта. Измените переменную AUTOLOAD
следующим образом:
$ f3 -> set ( ' AUTOLOAD ' , ' admin/autoload/; user/autoload/; default/ ' );
Важно: за исключением расширения .php, имя класса и имя файла должны быть идентичны, чтобы платформа правильно автоматически загрузила ваш класс. Базовое имя этого файла должно быть идентично вызову вашего класса, например, F3 будет искать Foo/BarBaz.php
или foo/barbaz.php
когда обнаружит new FooBarBaz
в вашем приложении.
AUTOLOAD
позволяет иерархиям классов находиться в подпапках с одинаковыми именами, поэтому, если вы хотите, чтобы платформа автоматически загружала класс в пространстве имен, который вызывается следующим образом:
$ f3 -> set ( ' AUTOLOAD ' , ' autoload/ ' );
$ obj = new Gadgets iPad ;
Вы можете создать иерархию папок, имеющую ту же структуру. Предполагая, что /var/www/html/
является корнем вашего веб-сайта, F3 будет искать класс в /var/www/html/autoload/gadgets/ipad.php
. Файл ipad.php
должен иметь следующий минимальный код:
namespace Gadgets ;
class iPad {}
Помните: все имена каталогов в Fat-Free должны заканчиваться косой чертой. Вы можете назначить путь поиска для автозагрузчика следующим образом:
$ f3 -> set ( ' AUTOLOAD ' , ' main/;aux/ ' );
F3, будучи структурой, поддерживающей пространство имен, позволяет использовать метод в классе с пространством имен в качестве обработчика маршрута, и существует несколько способов сделать это. Чтобы вызвать статический метод: -
$ f3 -> set ( ' AUTOLOAD ' , ' classes/ ' );
$ f3 -> route ( ' GET|POST / ' , ' MainHome::show ' );
Приведенный выше код вызовет статический метод show()
класса Home
в пространстве имен Main
. Home
класс должен быть сохранен в classes/main/home.php
чтобы он загружался автоматически.
Если вы предпочитаете работать с объектами: -
$ f3 -> route ( ' GET|POST / ' , ' MainHome->show ' );
создаст экземпляр класса Home
во время выполнения и после этого вызовет метод show()
.
В F3 есть несколько прослушивателей событий маршрутизации, которые могут помочь вам улучшить поток и структуру классов контроллера. Предположим, у вас есть маршрут, определенный следующим образом: -
$ f3 -> route ( ' GET / ' , ' Main->home ' );
Если приложение получает HTTP-запрос, соответствующий указанному выше маршруту, F3 создает экземпляр Main
, но перед выполнением метода home()
платформа ищет в этом классе метод с именем beforeRoute()
. В случае обнаружения F3 запускает код, содержащийся в обработчике событий beforeRoute()
, перед передачей управления методу home()
. Как только это будет выполнено, платформа ищет обработчик событий afterRoute()
. Как и beforeRoute()
, метод выполняется, если он определен.
Вот еще одна вкусность F3: -
$ f3 -> route ( ' GET /products/@action ' , ' Products->@action ' );
Если ваше приложение получает запрос, скажем, /products/itemize
, F3 извлечет строку 'itemize'
из URL-адреса и передаст ее токену @action
в обработчике маршрута. Затем F3 найдет класс с именем Products
и выполнит метод itemize()
.
Обработчики динамических маршрутов могут иметь различные формы:
// static method
$ f3 -> route ( ' GET /public/@genre ' , ' Main::@genre ' );
// object mode
$ f3 -> route ( ' GET /public/@controller/@action ' , ' @controller->@action ' );
F3 вызывает ошибку HTTP 404 Not Found
во время выполнения, если он не может передать управление классу или методу, связанному с текущим маршрутом, то есть неопределенному классу или методу.
Шаблоны маршрутизации могут содержать модификаторы, которые предписывают платформе основывать свое решение о маршрутизации на типе HTTP-запроса:
$ f3 -> route ( ' GET /example [ajax] ' , ' Page->getFragment ' );
$ f3 -> route ( ' GET /example [sync] ' , ' Page->getFull ' );
Первый оператор направит HTTP-запрос на обратный вызов Page->getFragment()
только в том случае, если сервер получит заголовок X-Requested-With: XMLHttpRequest
(объект AJAX). Если обнаружен обычный (синхронный) запрос, F3 просто перейдет к следующему соответствующему шаблону и в этом случае выполнит обратный вызов Page->getFull()
.
Если в шаблоне маршрутизации не определены модификаторы, то запросы AJAX и синхронного типа перенаправляются к указанному обработчику.
Модификаторы шаблонов маршрутов также распознаются $f3->map()
.
Переменные, определенные в Fat-Free, являются глобальными, т. е. к ним может получить доступ любой компонент MVC. Глобальные переменные Framework не идентичны глобальным переменным PHP. Переменная F3 с именем content
не идентична PHP $content
. F3 сам по себе является предметно-ориентированным языком и поддерживает собственную отдельную таблицу символов для системных и прикладных переменных. Фреймворк, как и любая хорошо спроектированная объектно-ориентированная программа, не загрязняет глобальное пространство имен PHP константами, переменными, функциями или классами, которые могут конфликтовать с каким-либо приложением. В отличие от других фреймворков, F3 не использует оператор PHP define()
. Все константы платформы ограничены классами.
Чтобы присвоить значение переменной Fat-Free:
$ f3 -> set ( ' var ' ,value); // or
$ f3 -> var =value;
$ f3 -> set ( ' hello.world ' , ' good morning ' ); // translates to : 'hello' == array ( 'world' = > 'good morning' )
$ f3 ->{ ' hello.world ' }= ' good morning ' ; // same as prior statement
Примечание. Переменные Fat-Free принимают все типы данных PHP, включая объекты и анонимные функции.
Чтобы установить несколько переменных одновременно:
$ f3 -> mset (
[
' foo ' => ' bar ' ,
' baz ' => 123
]
);
Чтобы получить значение переменной платформы с именем var
:
echo $ f3 -> get ( ' var ' ); // or
echo $ f3 -> var ;
Чтобы удалить переменную Fat-Free из памяти, если она вам больше не нужна (удалить ее, чтобы она не мешала другим функциям/методам), используйте метод: -
$ f3 -> clear ( ' var ' ); // or
unset( $ f3 -> var );
Чтобы узнать, была ли переменная определена ранее:
$ f3 -> exists ( ' var ' ) //
isset ( $ f3 -> var )
F3 поддерживает собственную таблицу символов для переменных платформы и приложения, которые не зависят от PHP. Некоторые переменные отображаются в глобальные переменные PHP. SESSION
в Fat-Free эквивалентен $_SESSION
, а REQUEST
соответствует $_REQUEST
. Рекомендуется использовать переменные платформы вместо PHP, чтобы облегчить передачу данных между различными функциями, классами и методами. У них есть и другие преимущества:
SESSION
также изменяет базовый PHP $_SESSION
. Изменение последнего также приводит к изменению аналога фреймворка. Fat-Free не просто хранит переменные и их значения. Он также может автоматизировать управление сеансами и другие вещи. Присвоение или получение значения через переменную SESSION
клавиши F3 автоматически запускает сеанс. Если вы используете $_SESSION
(или функции, связанные с сеансом) напрямую вместо переменной платформы SESSION
, ваше приложение становится ответственным за управление сеансами.
Как правило, переменные платформы не сохраняются между HTTP-запросами. Только SESSION
и COOKIE
(и их элементы), которые сопоставлены с глобальными переменными PHP $_SESSION
и $_COOKIE
освобождаются от не сохраняющего состояния HTTP.
Существует несколько предопределенных глобальных переменных, используемых внутри Fat-Free, и вы, безусловно, можете использовать их в своем приложении. Убедитесь, что вы знаете, что делаете. Изменение некоторых глобальных переменных Fat-Free может привести к неожиданному поведению платформы.
Фреймворк имеет несколько переменных, которые помогут вам организовать структуру файлов и каталогов. Мы увидели, как можно автоматизировать загрузку классов с помощью AUTOLOAD
. Существует глобальная переменная UI
, которая содержит путь, указывающий расположение ваших представлений/шаблонов HTML. DEBUG
— это еще одна переменная, которую вы будете часто использовать во время разработки приложений, и она используется для настройки детализации трассировок ошибок.
Обратитесь к Краткому справочнику, если вам нужен полный список встроенных переменных платформы.
Переменная платформы может содержать любое количество букв, цифр и знаков подчеркивания. Он должен начинаться с альфа-символа и не должен содержать пробелов. Имена переменных чувствительны к регистру.
F3 использует все заглавные буквы для внутренних предопределенных глобальных переменных. Ничто не мешает вам использовать имена переменных, состоящие из заглавных букв, в вашей собственной программе, но, как правило, придерживайтесь нижнего регистра (или верблюжьего регистра), когда вы настраиваете свои собственные переменные, чтобы избежать любого возможного конфликта с текущими и будущими выпусками платформы. .
Не следует использовать зарезервированные слова PHP, такие как if
, for
, class
, default
и т. д., в качестве имен переменных платформы. Это может привести к непредсказуемым результатам.
F3 также предоставляет ряд инструментов, которые помогут вам с переменными платформы.
$ 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 также предоставляет некоторые примитивные методы для работы с переменными массива:
$ 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
В отличие от других платформ с жесткой структурой папок, F3 дает вам большую гибкость. Вы можете иметь структуру папок, которая выглядит следующим образом (слова в скобках, написанные заглавными буквами, обозначают переменные платформы F3, которые необходимо настроить):
/ (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)
Не стесняйтесь организовывать свои файлы и каталоги так, как захотите. Просто установите соответствующие глобальные переменные F3. Если вам нужен действительно безопасный сайт, Fat-Free даже позволяет хранить все ваши файлы в каталоге, недоступном из Интернета. Единственное требование — оставить index.php
, .htaccess
и ваши общедоступные файлы, такие как CSS, JavaScript, изображения и т. д., в пути, видимом для вашего браузера.
Fat-Free генерирует собственные страницы ошибок HTML со трассировкой стека, которые помогут вам в отладке. Вот пример: -
Внутренняя ошибка сервера
strpos() ожидает как минимум 2 параметра, задано 0
• var/html/dev/main.php:96 strpos() • var/html/dev/index.php:16 Base->run()
Если вы чувствуете, что это слишком просто или хотите сделать что-то другое при возникновении ошибки, вы можете создать свой собственный обработчик ошибок:
$ 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 поддерживает глобальную переменную, содержащую сведения о последней ошибке, произошедшей в вашем приложении. Переменная ERROR
представляет собой массив, структурированный следующим образом:
ERROR.code - displays the error code (404, 500, etc.)
ERROR.status - header and page title
ERROR.text - error context
ERROR.trace - stack trace
При разработке приложения лучше всего установить максимальный уровень отладки, чтобы можно было отследить все ошибки до их основной причины:
$ f3 -> set ( ' DEBUG ' , 3 );
Просто вставьте команду в последовательность загрузки вашего приложения.
Как только ваше приложение будет готово к выпуску, просто удалите оператор из вашего приложения или замените его следующим:
$ f3 -> set ( ' DEBUG ' , 0 );
Это приведет к подавлению вывода трассировки стека на любой сгенерированной системой странице ошибки HTML (поскольку она не предназначена для просмотра посетителями вашего сайта).
DEBUG
может иметь значения в диапазоне от 0 (трассировка стека подавлена) до 3 (наиболее подробный).
Не забывайте! Трассировки стека могут содержать пути, имена файлов, команды базы данных, имена пользователей и пароли. Вы можете подвергнуть свой веб-сайт ненужным рискам безопасности, если не установите для глобальной переменной DEBUG
значение 0 в производственной среде.
Если ваше приложение должно настраиваться пользователем, F3 предоставляет удобный метод чтения файлов конфигурации для настройки вашего приложения. Таким образом, вы и ваши пользователи сможете настраивать приложение, не изменяя PHP-код.
Вместо создания PHP-скрипта, содержащего следующий пример кода:
$ 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 ]);
Вы можете создать файл конфигурации, который делает то же самое:
[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
Вместо длинных операторов $f3->set()
в вашем коде вы можете указать платформе загрузить файл конфигурации в качестве замены кода. Давайте сохраним приведенный выше текст как setup.cfg. Затем мы можем вызвать его с помощью простого: -
$ f3 -> config ( ' setup.cfg ' );
Строковые значения не обязательно заключать в кавычки, если только вы не хотите включать начальные или конечные пробелы. Если запятую следует рассматривать как часть строки, заключите ее в двойные кавычки. В противном случае значение будет рассматриваться как массив (запятая используется как разделитель элементов массива). Строки могут занимать несколько строк: -
[globals]
str = " this is a
very long
string "
F3 также дает вам возможность определять маршруты HTTP в файлах конфигурации:
[routes]
GET /=home
GET / 404 =App->page404
GET /page/@ num =Page->@controller
Карты маршрутов также могут быть определены в файлах конфигурации: -
[maps]
/ blog =BlogLogin
/blog/@ controller =Blog@controller
Заголовки разделов [globals]
, [routes]
и [maps]
являются обязательными. Вы можете объединить оба раздела в одном файле конфигурации, хотя рекомендуется иметь [routes]
и [maps]
в отдельном файле. Таким образом, вы можете разрешить конечным пользователям изменять некоторые флаги, специфичные для приложения, и в то же время запретить им вмешиваться в вашу логику маршрутизации.
Пользовательский интерфейс, такой как страница HTML, должен быть независимым от базового кода PHP, связанного с маршрутизацией и бизнес-логикой. Это фундаментально для парадигмы MVC. Базовая версия, такая как преобразование <h3>
в <p>
, не должна требовать изменения кода вашего приложения. Точно так же преобразование простого маршрута, такого как GET /about
, в GET /about-us
не должно оказывать никакого влияния на ваш пользовательский интерфейс и бизнес-логику (представление и модель в MVC или представление и метод в RMR).
Смешание программирования конструкций и компонентов пользовательского интерфейса в одном файле, таких как кодирование спагетти, делает будущее обслуживание приложения кошмаром.
F3 поддерживает PHP в качестве шаблонного двигателя. Взгляните на этот фрагмент HTML, сохраненный как template.htm
:-.
< p > Hello, < ?php echo $name; ? > ! </ p >
Если на вашем сервере включены короткие теги, это тоже должно работать:-
< p > Hello, < ?= $name ? > </ p >
Чтобы отобразить этот шаблон, вы можете иметь PHP-код, который выглядит так (хранится в файле отдельно от шаблона):-
$ 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 ();
Единственная проблема с использованием PHP в качестве шаблонного двигателя, из -за встроенного PHP -кода в этих файлах, - это сознательные усилия, необходимые для того, чтобы придерживаться руководящих принципов по разделению проблем и сопротивления искушению смешивания бизнес -логики с вашим пользовательским интерфейсом.
В качестве альтернативы PHP вы можете использовать собственный шаблонный двигатель F3. Приведенный выше фрагмент HTML может быть переписан как:-
< p > Hello, {{ @name }}! </ p >
и код, необходимый для просмотра этого шаблона:-
$ 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 ();
Как и токены маршрутизации, используемые для ловли переменных в URL -адресах (до сих пор помните пример GET /brew/@count
в предыдущем разделе?), Токены шаблонов F3 начинаются с символа @
, за которым следует ряд букв и цифр, заключенных в кудрявые скобки. Первым персонажем должен быть альфа. Токены шаблонов имеют переписку один на один с структуру переменными. Фтруктура автоматически заменяет токен со значением, хранящимся в переменной с тем же именем.
В нашем примере F3 заменяет токен @name
в нашем шаблоне значением, которое мы назначили переменной имени. Во время выполнения вывод вышеуказанного кода будет:-
< p > Hello, world </ p >
Беспокоились о производительности шаблонов F3? Во время выполнения фреймворк анализируется и компилирует/преобразует шаблон F3 в код PHP в первый раз, когда он отображается через $template->render()
. Затем фреймворк использует этот скомпилированный код во всех последующих вызовах. Следовательно, производительность должна быть такой же, как шаблоны PHP, если не лучше из -за оптимизации кода, выполняемой компилятором шаблона, когда участвуют более сложные шаблоны.
Независимо от того, используете ли вы шаблонный двигатель PHP или собственный F3, визуализация шаблона может быть значительно быстрее, если на вашем сервере есть APC, Wincache или Xcache.
Как упоминалось ранее, структуры переменные могут содержать любой тип данных PHP. Тем не менее, использование некалярных типов данных в шаблонах F3 может дать странные результаты, если вы не будете осторожны. Выражения в кудрявых скобках всегда будут оценены и преобразованы в строку. Вы должны ограничить переменные пользовательского интерфейса простыми скалярами:- string
, integer
, boolean
или float
Data.
Но как насчет массивов? FAT FAT распознает массивы, и вы можете использовать их в своих шаблонах. У вас может быть что-то вроде:-
< p > {{ @buddy[0] }}, {{ @buddy[1] }}, and {{ @buddy[2] }} </ p >
И заполнить массив @buddy
в вашем коде PHP, прежде чем подавать шаблон:-
$ f3 -> set ( ' buddy ' ,[ ' Tom ' , ' Dick ' , ' Harry ' ]);
Однако, если вы просто вставите {{ @buddy }}
в свой шаблон, PHP заменит его на 'Array'
потому что он преобразует токен в строку. PHP, с другой стороны, генерирует Array to string conversion
во время выполнения.
F3 позволяет вам внедрять выражения в шаблоны. Эти выражения могут принимать различные формы, такие как арифметические расчеты, логические выражения, константы PHP и т. Д. Вот несколько примеров:-
{{ 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 }}
Дополнительное примечание о выражении массива: обратите внимание, что @foo.@bar
- это строка, Concatenation $foo.$bar
), тогда как @foo.bar
переводится на $foo['bar']
. Если $foo[$bar]
- это то, что вы намеревались, используйте обычную нотацию @foo[@bar]
.
Переменные структуры могут также содержать анонимные функции:
$ f3 -> set ( ' func ' ,
function ( $ a , $ b ) {
return $ a . ' , ' . $ b ;
}
);
Двигатель шаблона F3 будет интерпретировать токен, как и ожидалось, если вы указате следующее выражение:
{{ @func('hello','world') }}
Простая переменная замена - это одна вещь, которую имеют все шаблонные двигатели. Без жира больше в рукавах:-
< include href =" header.htm " />
Директива будет внедрить содержимое шаблона Header.htm в точную позицию, где указана директива. Вы также можете иметь динамический контент в форме:-
< include href =" {{ @content }} " />
Практическое использование для такой шаблонной директивы - это когда у вас есть несколько страниц с общим макетом HTML, но с различным содержанием. Инструктировать структуру для вставки субъекта в ваш основной шаблон так же просто, как написание следующего кода 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 ' );
Субтурист может, в свою очередь, содержать любое количество директив. F3 допускает неограниченные вложенные шаблоны.
Вы можете указать имена файлов с чем -то другим, кроме расширения файлов .htm или .html, но их проще просмотреть в вашем веб -браузере на этапе разработки и отладки. Шаблонный двигатель не ограничивается рендерингом HTML -файлов. На самом деле вы можете использовать механизм шаблона для отображения других видов файлов.
Директива <include>
также имеет необязательный if
, поэтому вы можете указать условие, которое необходимо удовлетворить до того, как вставлен подраздел.
< include if =" {{ count(@items) }} " href =" items.htm " />
В ходе написания/отладки программ F3 и шаблонов проектирования могут быть случаи, когда может быть удобно отключение отображения блока HTML. Вы можете использовать директиву <exclude>
для этой цели:-
< exclude >
< p > A chunk of HTML we don't want displayed at the moment </ p >
</ exclude >
Это как <!-- comment -->
HTML-тег комментариев, но директива <exclude>
делает HTML-блок совершенно невидимым после того, как шаблон отображается.
Вот еще один способ исключить контент шаблона или добавление комментариев:-
{* < p > A chunk of HTML we don't want displayed at the moment </ p > *}
Другая полезная функция шаблона - директива <check>
. Это позволяет вам встроить фрагмент HTML в зависимости от оценки определенного условия. Вот несколько примеров:-
< 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 >
Вы можете иметь столько вложенных директивах <check>
, сколько вам нужно.
Выражение F3 внутри атрибута IF, которое приравнивается к NULL
, пустой строке, логической FALSE
, пустого массива или нуля, автоматически вызывает <false>
. Если ваш шаблон не имеет блока <false>
, то теги «Открытие <true>
и «Закрытие» необязательны:-
< check if =" {{ @loggedin }} " >
< p > HTML chunk to be included if condition is true </ p >
</ check >
Без жира также может обрабатывать повторяющиеся блоки HTML:-
< repeat group =" {{ @fruits }} " value =" {{ @fruit }} " >
< p > {{ trim(@fruit) }} </ p >
</ repeat >
Атрибут group
@fruits
внутри директивы <repeat>
должен быть массивом и должен быть установлен в вашем коде PHP соответственно:-
$ f3 -> set ( ' fruits ' ,[ ' apple ' , ' orange ' , ' banana ' ]);
Ничего не получено, назначив значение @fruit
в коде вашего приложения. Без жира игнорирует любое предустановленное значение, которое он может иметь, потому что она использует переменную для представления текущего элемента во время итерации над группой. Вывод вышеуказанного фрагмента шаблона HTML и соответствующий код PHP становится:-
< p > apple </ p >
< p > orange </ p >
< p > banana </ p >
Структура допускает неограниченное гнездование блоков <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 >
Примените следующую команду F3:-
$ f3 -> set ( ' div ' ,
[
' coffee ' =>[ ' arabica ' , ' barako ' , ' liberica ' , ' kopiluwak ' ],
' tea ' =>[ ' darjeeling ' , ' pekoe ' , ' samovar ' ]
]
);
В результате вы получаете следующий фрагмент 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 >
Удивительно, не так ли? И единственное, что вам нужно было сделать в PHP, - это определить содержимое одного переменного div
F3, чтобы заменить токен @div
. FAT делает как программирование, так и дизайн веб-шаблонов очень простым.
Атрибут value
Директивы <repeat>
шаблона возвращает значение текущего элемента в итерации. Если вам нужно получить клавишу массива текущего элемента, вместо этого используйте атрибут key
. key
атрибут необязательно.
<repeat>
также имеет дополнительный атрибут счетчика, который можно использовать следующим образом:-
< repeat group =" {{ @fruits }} " value =" {{ @fruit }} " counter =" {{ @ctr }} " >
< p class =" {{ @ctr%2?'odd':'even' }} " > {{ trim(@fruit) }} </ p >
</ repeat >
Внутренне, шаблонный двигатель F3 записывает количество итераций цикла и сохраняет это значение в переменной/токен @ctr
, которая используется в нашем примере для определения классификации ODD/равно.
Если вам придется вставить токены F3 в раздел <script>
или <style>
вашего шаблона, структура все равно заменит их обычным способом:-
< script type =" text/javascript " >
function notify ( ) {
alert ( 'You are logged in as: {{ @userID }}' ) ;
}
</ script >
Директивы шаблона встраивания внутри ваших тегов <script>
или <style>
не требуют особой обработки:-
< 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 >
По умолчанию FAT Free использует набор символов UTF-8, если не изменен. Вы можете переопределить это поведение, выпустив что-то вроде:-
$ f3 -> set ( ' ENCODING ' , ' ISO-8859-1 ' );
После того, как вы сообщите о рамках желаемого набора символов, F3 будет использовать его во всех шаблонах HTML и XML, пока не будет изменен снова.
Как упоминалось ранее в этом разделе, структура не ограничивается шаблонами HTML. Вы можете обрабатывать XML -шаблоны так же хорошо. Механики в значительной степени похожи. У вас по -прежнему есть одинаковые {{ @variable }}
и {{ expression }}
токены, <repeat>
, <check>
, <include>
и <exclude>
в вашем распоряжении. Просто скажите F3, что вы передаете XML-файл вместо HTML:-
echo Template:: instance ()-> render ( ' template.xml ' , ' application/xml ' );
Второй аргумент представляет собой тип типа MIME, представленного документа.
Компонент представления MVC охватывает все, что не подпадает под модель и контроллер, что означает, что ваша презентация может и должна включать все виды пользовательских интерфейсов, такие как RSS, электронная почта, RDF, FOAF, текстовые файлы и т. Д. Ниже показано, как отделить свою презентацию по электронной почте от бизнес-логики вашего приложения:-
MIME-Version: 1.0
Content-type: text/html; charset={{ @ENCODING }}
From: {{ @from }}
To: {{ @to }}
Subject: {{ @subject }}
< p > Welcome, and thanks for joining {{ @site }}! </ p >
Сохраните вышеупомянутый шаблон электронной почты как Welcome.txt. Связанный код F3 будет:-
$ 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 ' )
);
Совет: замените функцию smtp mail () на imap_mail (), если ваш скрипт связывается с сервером IMAP.
Теперь это не что -то? Конечно, если у вас есть пучка получателей электронной почты, вы будете использовать базу данных для заполнения первого имени, lastname и токенов электронной почты.
Вот альтернативное решение, используя плагин F3 SMTP:-
$ 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 поддерживает несколько языков прямо из коробки.
Во-первых, создайте файл словаря со следующей структурой (один файл на язык):-
<?php
return [
' love ' => ' I love F3 ' ,
' today ' => ' Today is {0,date} ' ,
' pi ' => ' {0,number} ' ,
' money ' => ' Amount remaining: {0,number,currency} '
];
Сохраните его как dict/en.php
. Давайте создадим еще один словарь, на этот раз для немецкого языка. Сохраните файл как dict/de.php
:-
<?php
return [
' love ' => ' Ich liebe F3 ' ,
' today ' => ' Heute ist {0,date} ' ,
' money ' => ' Restbetrag: {0,number,currency} '
];
Словари-не что иное, как пары ключевых значений. F3 автоматически создает структуру переменных на основе ключей в языковых файлах. Таким образом, легко внедрить эти переменные в виде токенов в ваши шаблоны. Используя механизм шаблона F3:-
< h1 > {{ @love }} </ h1 >
< p >
{{ @today,time() | format }}. < br />
{{ @money,365.25 | format }} < br />
{{ @pi }}
</ p >
И более длинная версия, которая использует PHP в качестве шаблонного двигателя:-
<?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>
Далее мы инструктируем F3 искать словари в dict/
Polder:-
$ f3 -> set ( ' LOCALES ' , ' dict/ ' );
Но как структура определяет, какой язык использовать? F3 сначала обнаружит его автоматически, сначала посмотрев на заголовки HTTP-запроса, в частности, заголовок Accept-Language
отправленный браузером.
Чтобы переопределить это поведение, вы можете запустить F3 для использования языка, указанного пользователем или приложением:-
$ f3 -> set ( ' LANGUAGE ' , ' de ' );
Примечание. В приведенном выше примере ключ PI существует только в английском словаре. Структура всегда будет использовать английский ( en
) в качестве запасного для заполнения клавиш, которые не присутствуют на указанном (или обнаруженном) языке.
Вы также можете создавать файлы словаря для вариантов языка, таких как en-US
, es-AR
и т. Д. В этом случае F3 сначала будет использовать язык языка (например, es-AR
). Если есть ключи, которые не существуют в варианте, структура будет искать ключ на корневом языке ( es
), а затем используйте файл языка en
в качестве окончательного отступления. Словарь пары клавишных значений становятся переменными F3 после ссылки. Убедитесь, что ключи не конфликтуют с какой-либо структурой переменной, созданной через $f3->set()
, $f3->mset()
или $f3->config()
.
Вы заметили, что в нашем предыдущем примере особенный 'Today is {0,date}'
? Многоязычная возможность F3 зависит от правил форматирования строки/сообщений проекта ICU. Структура использует свое собственное подмножество реализации форматирования форматирования строки ICU. Нет необходимости активировать расширение PHP intl
на сервере.
Еще одна вещь: F3 также может загружать файлы в стиле .ini в виде словари:-
love = " I love F3 "
today = " Today is {0,date} "
pi = " {0,number} "
money = " Amount remaining: {0,number,currency} "
Сохраните его как dict/en.ini
, чтобы фреймворк могла загружать его автоматически.
По умолчанию как обработчик, так и шаблонный двигатель избегает всех визуализированных переменных, т.е. преобразован в HTML -объекты, чтобы защитить вас от возможных XSS и атак впрыскивания кода. С другой стороны, если вы хотите передать действительные фрагменты HTML из кода приложения в свой шаблон:-
$ f3 -> set ( ' ESCAPE ' , FALSE );
Это может иметь нежелательные эффекты. Возможно, вы не хотите, чтобы все переменные проходили через бесчисленную беззаботную. FAT LEASS позволяет вам по отдельности бессмысленной. Для шаблонов F3:-
{{ @html_content | raw }}
В случае шаблонов PHP:-
<?php echo View:: instance ()-> raw ( $ html_content ); ?>
В качестве дополнения к автоматическому разбросанию переменных F3, структура также дает вам свободную руку при дезинфицирующем пользовательском вводе от HTML-форм:-
$ f3 -> scrub ( $ _GET , ' p; br; span; div; a ' );
Эта команда лишит все теги (кроме указанных во втором аргументе) и небезопасных символов из указанной переменной. Если переменная содержит массив, каждый элемент в массиве рекурсивно дезинфицируется. Если звездочка (*) передается как второй аргумент, $f3->scrub()
позволяет всем тегам HTML проходить через нетронутые и просто удалять небезопасные элементы управления.
FAT FAT предназначен для того, чтобы сделать работу по взаимодействию с базами данных SQL. Если вы не тот тип, чтобы погрузиться в подробности о SQL, но больше относитесь к обращению с объектно-ориентированными данными, вы можете перейти непосредственно к следующему разделу этого учебника. Однако, если вам нужно выполнить некоторые сложные задачи по обработке данных и оптимизации эффективности базы данных, SQL-это путь.
Создание связи с двигателем SQL, таким как MySQL, SQLite, SQL Server, Sybase и Oracle выполняется с использованием знакомой команды $f3->set()
. Подключение к базе данных SQLite будет:-
$ db = new DB SQL ( ' sqlite:/absolute/path/to/your/database.sqlite ' );
Другой пример, на этот раз с MySQL:-
$ db = new DB SQL (
' mysql:host=localhost;port=3306;dbname=mysqldb ' ,
' admin ' ,
' p455w0rD '
);
ХОРОШО. Это было легко, не так ли? Это в значительной степени, как вы бы сделали то же самое в обычном PHP. Вам просто нужно знать формат DSN базы данных, к которой вы подключаетесь. См. Раздел PDO руководства PHP.
Давайте продолжим наш код PHP:-
$ f3 -> set ( ' result ' , $ db -> exec ( ' SELECT brandName FROM wherever ' ));
echo Template:: instance ()-> render ( ' abc.htm ' );
Да, что здесь происходит? Разве мы не должны настраивать такие вещи, как PDO, заявления, курсоры и т. Д.? Простой ответ: вам не нужно. F3 упрощает все, заботясь обо всей тяжелой работе в бэкэнде.
На этот раз мы создаем шаблон HTML, такой как abc.htm
, который имеет как минимум следующее:-
< repeat group =" {{ @result }} " value =" {{ @item }} " >
< span > {{ @item.brandName }} </ span >
</ repeat >
В большинстве случаев набор команд SQL должен быть достаточно, чтобы генерировать готовую к веб-результату, чтобы вы могли напрямую использовать переменную массива result
в вашем шаблоне. Как бы то ни было, без жира не помешает вам войти в его внутренние внутренности обработчика SQL. Фактически, класс F3 DBSQL
происходит непосредственно из класса PDO
PHP, поэтому у вас все еще есть доступ к базовым компонентам PDO и примитивам, участвующим в каждом процессе, если вам нужен мелкозернистый контроль.
Вот еще один пример. Вместо одного оператора, предоставленного в качестве аргумента команды $db->exec()
, вы также можете передать массив операторов SQL:-
$ db -> exec (
[
' DELETE FROM diet WHERE food="cola" ' ,
' INSERT INTO diet (food) VALUES ("carrot") ' ,
' SELECT * FROM diet '
]
);
F3 достаточно умный, чтобы знать, что если вы передаете массив инструкций SQL, это указывает на пакетную транзакцию SQL. Вам не нужно беспокоиться о откатах и коммитов SQL, потому что структура автоматически вернется к начальному состоянию базы данных, если во время транзакции возникает какие -либо ошибки. В случае успеха F3 совершает все изменения, внесенные в базу данных.
Вы также можете начать и закончить транзакцию программно:-
$ 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 ();
Откат возникнет, если какое -либо из операторов столкнется с ошибкой.
Чтобы получить список всех инструкций базы данных:-
echo $ db -> log ();
Передача аргументов строковых аргументов к утверждениям SQL чревата опасностью. Рассмотрим это:-
$ db -> exec (
' SELECT * FROM users ' .
' WHERE username=" ' . $ f3 -> get ( ' POST.userID ' . ' " ' )
);
Если переменная POST
userID
не проходит какое-либо процесс санитарии данных, вредоносный пользователь может передать следующую строку и необратимо повредить вашу базу данных:-
admin " ; DELETE FROM users; SELECT " 1
К счастью, параметризованные запросы помогут вам смягчить эти риски:-
$ db -> exec (
' SELECT * FROM users WHERE userID=? ' ,
$ f3 -> get ( ' POST.userID ' )
);
Если F3 обнаруживает, что значение параметра/токена запроса является строкой, базовый уровень доступа к данным избегает строки и добавляет кавычки по мере необходимости.
Наш пример в предыдущем разделе будет намного безопаснее от инъекции SQL, если написано таким образом:-
$ db -> exec (
[
' DELETE FROM diet WHERE food=:name ' ,
' INSERT INTO diet (food) VALUES (?) ' ,
' SELECT * FROM diet '
],
[
array ( ' :name ' => ' cola ' ),
array ( 1 => ' carrot ' ),
NULL
]
);
F3 заполнен простыми в использовании объектно-релационных картинов (ORM), которые расположены между вашим приложением и вашими данными, что делает его намного проще и быстрее для написания программ, которые обрабатывают общие операции данных, такие как создание, получение, обновление, обновление, и удаление информации (CRUD) из баз данных SQL и NOSQL. Участники данных выполняют большую часть работы, отображая взаимодействие объектов PHP с соответствующими вопросами бэкэнд.
Предположим, у вас есть существующая база данных MySQL, содержащая таблицу пользователей вашего приложения. (SQLite, PostgreSQL, SQL Server, Sybase подойдет так же хорошо.) Он был бы создан с использованием следующей команды SQL:-
CREATE TABLE users (
userID VARCHAR ( 30 ),
password VARCHAR ( 30 ),
visits INT ,
PRIMARY KEY (userID)
);
Примечание: MongoDB-это двигатель базы данных NOSQL и без схемы. F3 имеет свою собственную быструю и легкую реализацию NoSQL, называемую JIG, которая использует PHP-сериализованные или кодируемые JSON плоские файлы. Эти слои абстракции не требуют жестких структур данных. Поля могут варьироваться от одной записи к другой. Они также могут быть определены или сброшены на лету.
Теперь вернемся к SQL. Во -первых, мы устанавливаем общение с нашей базой данных.
$ db = new DB SQL (
' mysql:host=localhost;port=3306;dbname=mysqldb ' ,
' admin ' ,
' wh4t3v3r '
);
Чтобы получить запись из нашей таблицы:-
$ user = new DB SQL Mapper ( $ db , ' users ' );
$ user -> load ([ ' userID=? ' , ' tarzan ' ]);
Первая строка интенсирует объект Mapper Data, который взаимодействует с таблицей users
в нашей базе данных. За сценой F3 извлекает структуру таблицы users
и определяет, какие поля (ы) определены как первичные ключи. На этом этапе объект Mapper еще не содержит данных (сухое состояние), так что $user
- не более чем структурированный объект, но он содержит методы, необходимые для выполнения основных операций CRUD и некоторых дополнений. Чтобы получить запись из нашей таблицы пользователей с помощью поля userID
содержащего строковое значение tarzan
, мы используем load() method
. Этот процесс называется «автоматическим гидратированием» объекта Mapper Data.
Легко, не так ли? F3 понимает, что таблица SQL уже имеет структурное определение, существующее в самом двигателе базы данных. В отличие от других структур, F3 не требует дополнительных объявлений классов (если вы не хотите расширить картины данных, чтобы соответствовать сложным объектам), никаких избыточных сопоставлений PHP-массива/объекта-объекта в поле (дублирование усилий), нет генераторов кодов (которые требуют кода Регенерация Если структура базы данных изменяется), нет глупых файлов XML/YAML для настройки ваших моделей, без лишних команд только для получения одной записи. С F3 простое изменение размера поля varchar
в MySQL не требует изменения в коде вашего приложения. В соответствии с MVC и «разделением проблем», администратор базы данных имеет столько контроля над данными (и структурами), сколько дизайнер шаблона имеет шаблоны HTML/XML.
Если вы предпочитаете работать с базами данных NOSQL, сходства в синтаксисе запросов являются поверхностными. В случае MongoDB Mapper, эквивалентный код будет:-
$ db = new DB Mongo ( ' mongodb://localhost:27017 ' , ' testdb ' );
$ user = new DB Mongo Mapper ( $ db , ' users ' );
$ user -> load ([ ' userID ' => ' tarzan ' ]);
С помощью джига синтаксис похож на шаблонный двигатель F3:-
$ db = new DB Jig ( ' db/data/ ' , DB Jig:: FORMAT_JSON );
$ user = new DB Jig Mapper ( $ db , ' users ' );
$ user -> load ([ ' @userID=? ' , ' tarzan ' ]);
Фреймворк автоматически отображает visits
поля в нашей таблице с свойством Mapper Data во время создания объекта, то есть $user=new DBSQLMapper($db,'users');
. Как только объект будет создан, $user->password
и $user->userID
будут отображаться в поле password
и userID
в нашей таблице соответственно.
Вы не можете добавить или удалить поля с отображением или изменить структуру таблицы с помощью ORM. Вы должны сделать это в MySQL, или в любом двигателе базы данных, который вы используете. После того, как вы внесете изменения в свой двигатель базы данных, FAT FAT автоматически синхронизирует новую структуру таблицы с вашим объектом Mapper Data при запуске вашего приложения.
F3 выводит структуру Mapper Data непосредственно из схемы базы данных. Никаких догадок. Он понимает различия между двигателями баз данных MySQL, SQLite, MSSQL, SYBASE и PostgreSQL.
Идентификаторы SQL не должны использовать зарезервированные слова и должны быть ограничены буквенно-цифровыми символами AZ
, 0-9
и подчеркивающим символом ( _
). Имена столбцов, содержащие пространства (или специальные символы) и окруженные кавычками в определении данных, не совместимы с ORM. Они не могут быть представлены должным образом как свойства объекта PHP.
Допустим, мы хотим увеличить количество посещений пользователя и обновить соответствующую запись в нашей таблице пользователей, мы можем добавить следующий код:-
$ user -> visits ++;
$ user -> save ();
Если мы хотим вставить запись, мы следим за этим процессом:-
$ 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 ();
Мы все еще используем тот же метод save()
. Но как F3 узнает, когда запись должна быть вставлена или обновлена? В то время, когда объект Mapper Data Автогидратируется с помощью поиска записи, структура отслеживает основные ключи записи (или _id
, в случае MongoDB и JIG) - чтобы он знал, какую запись должна быть обновлена или удалена - даже Когда значения первичных ключей изменяются. Программно -гидратированная карта данных - значения которых не были извлечены из базы данных, но заполненные приложением - не будут иметь память о предыдущих значениях в своих основных ключах. То же самое относится и к MongoDB и JIG, но с использованием объекта _id
в качестве ссылки. Таким образом, когда мы создали создание объекта $user
и заполнили его свойства значениями из нашей программы - без получения записи из пользовательской таблицы, F3 знает, что он должен вставить эту запись.
Объект Mapper не будет пустым после save()
. Если вы хотите добавить новую запись в свою базу данных, вы должны сначала обезвожить Mapper:-
$ user -> reset ();
$ user -> userID = ' cheetah ' ;
$ user -> password = password_hash ( ' unknown ' , PASSWORD_BCRYPT , [ ' cost ' => 12 ]);
$ user -> save ();
Вызов save()
во второй раз без вызова reset()
просто обновит записи, на которую указана в настоящее время Mapper.
Хотя проблема наличия первичных ключей во всех таблицах в вашей базе данных является аргументированной, F3 не мешает вам создавать объект Mapper Data, который связывается с таблицей, не содержащей первичных ключей. Единственным недостатком является: вы не можете удалить или обновить сопоставленную запись, потому что F3 нет, чтобы определить, на какую запись вы говорите, плюс тот факт, что позиционные ссылки не являются надежными. Идентификаторы строк не переносимы по разным двигателям SQL и не могут быть возвращены драйвером базы данных PHP.
Чтобы удалить отображение записи из нашей таблицы, вызовите метод erase()
на автогидратированном Mapper Data. Например:-
$ user = new DB SQL Mapper ( $ db , ' users ' );
$ user -> load ([ ' userID=? AND password=? ' , ' cheetah ' , ' ch1mp ' ]);
$ user -> erase ();
Синтаксис запросов JIG был бы немного похожим:-
$ user = new DB Jig Mapper ( $ db , ' users ' );
$ user -> load ([ ' @userID=? AND @password=? ' , ' cheetah ' , ' chimp ' ]);
$ user -> erase ();
И эквивалент MongoDB будет:-
$ user = new DB Mongo Mapper ( $ db , ' users ' );
$ user -> load ([ ' userID ' => ' cheetah ' , ' password ' => ' chimp ' ]);
$ user -> erase ();
Чтобы выяснить, был ли наш карт данных гидратирован или нет:-
if ( $ user -> dry ())
echo ' No record matching criteria ' ;
Мы рассмотрели грандировщиков Crud. Есть несколько дополнительных методов, которые вы можете найти полезными:-
$ f3 -> set ( ' user ' , new DB SQL Mapper ( $ db , ' users ' ));
$ f3 -> get ( ' user ' )-> copyFrom ( ' POST ' );
$ f3 -> get ( ' user ' )-> save ();
Обратите внимание, что мы также можем использовать без жиров переменные в качестве контейнеров для объектов Mapper. Метод copyFrom()
увлажняет объект Mapper с элементами из переменной массивы Framework, клавиши массива, из которых должны иметь имена, идентичные свойствам объекта Mapper, которые, в свою очередь, соответствуют именам поля записи. Таким образом, когда отправляется веб -форма (при условии, что атрибут имени HTML устанавливается на userID
), содержимое этого поля ввода передается в $_POST['userID']
, дублируется F3 в своем POST.userID
переменном и сохраняется на Полевое поле $user->userID
в базе данных. Процесс становится очень простым, если у них все имеют идентично названные элементы. Последовательность в клавишах массива, т.е. имена токенов шаблона, имена переменных переменных и имен поля - ключ :)
С другой стороны, если мы хотим получить запись и скопировать значения поля в структуру переменной для последующего использования, например, рендеринг шаблона:-
$ f3 -> set ( ' user ' , new DB SQL Mapper ( $ db , ' users ' ));
$ f3 -> get ( ' user ' )-> load ([ ' userID=? ' , ' jane ' ]);
$ f3 -> get ( ' user ' )-> copyTo ( ' POST ' );
Затем мы можем назначить {{ @post.userid}} атрибут значения поля ввода. Подводя итог, поля ввода HTML будет выглядеть следующим образом:-
< input type =" text " name =" userID " value =" {{ @POST.userID }} " />
save()
, update()
, copyFrom()
Методы Mapper Data и параметризованные варианты load()
и erase()
безопасны от инъекции SQL.
По умолчанию метод Mapper's load()
получает только первую запись, которая соответствует указанным критериям. Если у вас есть более одного, которое соответствует тому же условию, что и первая загруженная запись, вы можете использовать метод skip()
для навигации:-
$ 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 );
Вы можете использовать $user->next()
в качестве замены $user->skip()
и $user->prev()
если вы думаете, что это дает больше смысла $user->skip(-1)
.
Используйте метод dry()
, чтобы проверить, маневрировали ли вы за пределами набора результатов. dry()
вернет True, если вы попробуете skip(-1)
на первой записи. Это также вернет истину, если вы skip(1)
на последней записи, которая соответствует критериям поиска.
Метод load()
принимает второй аргумент: массив параметров, содержащих пары ключей, такие как:-
$ user -> load (
[ ' visits>? ' , 3 ],
[
' order ' => ' userID DESC '
'offset'=> 5 ,
' limit ' => 3
]
);
Если вы используете MySQL, запрос переводится как:-
SELECT * FROM users
WHERE visits > 3
ORDER BY userID DESC
LIMIT 3 OFFSET 5 ;
Это один из способов представления данных в небольших кусках. Вот еще один способ нанесения на стражу:-
$ page = $ user -> paginate ( 2 , 5 ,[ ' visits>? ' , 3 ]);
В приведенном выше сценарии F3 будет получать записи, которые соответствуют критериям 'visits>3'
. Затем он ограничит результаты 5 записями (на страницу), начиная с страницы Offset 2 (на основе 0). Структура вернет массив, состоящий из следующих элементов:-
[subset] array of mapper objects that match the criteria
[count] number of subsets available
[pos] actual subset position
Возвращенное положение подмножества будет нулевой, если первый аргумент paginate()
является отрицательным числом или превышает количество найденных подмножеств.
Существуют случаи, когда вам нужно получить вычисленное значение поля или поперечное значение из другой таблицы. Введите виртуальные поля. SQL Mini-Orm позволяет вам работать над данными, полученными из существующих областей.
Предположим, у нас есть следующая таблица, определенная как:-
CREATE TABLE products
productID VARCHAR ( 30 ),
description VARCHAR ( 255 ),
supplierID VARCHAR ( 30 ),
unitprice DECIMAL ( 10 , 2 ),
quantity INT ,
PRIMARY KEY (productID)
);
Поле totalprice
не существует, поэтому мы можем сообщить о рамках для запроса из двигателя базы данных арифметический продукт двух полей:-
$ item = new DB SQL Mapper ( $ db , ' products ' );
$ item -> totalprice = ' unitprice*quantity ' ;
$ item -> load ([ ' productID=:pid ' , ' :pid ' => ' apple ' ]);
echo $ item -> totalprice ;
Приведенный выше фрагмент кода определяет виртуальное поле, называемое totalprice
, которое вычисляется путем умножения unitprice
на quantity
. Mapper SQL сохраняет это правило/формулу, поэтому, когда придет время извлечь запись из базы данных, мы можем использовать виртуальное поле, как регулярное поле.
Вы можете иметь более сложные виртуальные поля:-
$ item -> mostNumber = ' MAX(quantity) ' ;
$ item -> load ();
echo $ item -> mostNumber ;
На этот раз структура извлекает продукт с наибольшим количеством количества (обратите внимание, что метод load()
не определяет каких -либо критериев, поэтому будут обработаны все записи в таблице). Конечно, виртуальное поле mostNumber
по -прежнему даст вам правильную цифру, если вы хотите ограничить выражение определенной группой записей, которые соответствуют указанным критериям.
Вы также можете получить значение из другой таблицы:-
$ item -> supplierName =
' SELECT name FROM suppliers ' .
' WHERE products.supplierID=suppliers.supplierID ' ;
$ item -> load ();
echo $ item -> supplierName ;
Каждый раз, когда вы загружаете запись из таблицы продуктов, ORM перекрестно ссылается на supplerID
в таблице products
с supplierID
в таблице suppliers
.
Чтобы уничтожить виртуальное поле, используйте unset($item->totalPrice);
. Выражение isset($item->totalPrice)
возвращает True, если виртуальное поле totalPrice
было определено или неверно, если иное.
Помните, что виртуальное поле должно быть определена до поиска данных. ORM не выполняет фактические вычисления, ни получение результатов из другой таблицы. Это двигатель базы данных, который выполняет всю тяжелую работу.
Если у вас нет необходимости в навигации по записи за рекордом, вы можете получить целую партию записей за один выстрел:-
$ frequentUsers = $ user -> find ([ ' visits>? ' , 3 ],[ ' order ' => ' userID ' ]);
Синтаксис запроса Jig Mapper имеет небольшое сходство:-
$ frequentUsers = $ user -> find ([ ' @visits>? ' , 3 ],[ ' order ' => ' userID ' ]);
Эквивалентный код с использованием MongoDB Mapper:-
$ frequentUsers = $ user -> find ([ ' visits ' =>[ ' $gt ' => 3 ]],[ ' userID ' => 1 ]);
Метод find()
ищет таблицу users
для записей, которые соответствуют критериям, сортируют результат по userID
и возвращает результат как массив объектов Mapper. find('visits>3')
отличается от load('visits>3')
. Последний относится к текущему объекту $user
. find()
не влияет на skip()
.
ВАЖНО: Объявление пустого условия, нулевого или строки нулевой длины в качестве первого аргумента find()
или load()
получит все записи. Убедитесь, что вы знаете, что делаете - вы можете превзойти PHP Memory_limit в больших таблицах или коллекциях.
Метод find()
имеет следующий синтаксис:-
find (
$ criteria ,
[
' group ' => ' foo ' ,
' order ' => ' foo,bar ' ,
' limit ' => 5 ,
' offset ' => 0
]
);
Найти () возвращает массив объектов. Каждый объект является отображением записи, которая соответствует указанным критериям. :-
$ place = new DB SQL Mapper ( $ db , ' places ' );
$ list = $ place -> find ( ' state="New York" ' );
foreach ( $ list as $ obj )
echo $ obj -> city . ' , ' . $ obj -> country ;
Если вам нужно преобразовать объект Mapper в ассоциативный массив, используйте метод cast()
:-
$ array = $ place -> cast ();
echo $ array [ ' city ' ]. ' , ' . $ array [ ' country ' ];
Чтобы получить количество записей в таблице, которые соответствуют определенному условию, используйте метод count()
.
if (! $ user -> count ([ ' visits>? ' , 10 ]))
echo ' We need a better ad campaign! ' ;
Существует также метод select()
, который похож на find()
, но обеспечивает более мелкозернистый контроль над возвращенными полями. Он имеет SQL-подобный синтаксис:-
select (
' foo, bar, MIN(baz) AS lowest ' ,
' foo > ? ' ,
[
' group ' => ' foo, bar ' ,
' order ' => ' baz ASC ' ,
' limit ' => 5 ,
' offset ' => 3
]
);
Подобно методу find()
, select()
не изменяет содержимое объекта Mapper. Он служит только удобным методом для запроса таблицы с картой. Возвращаемое значение обоих методов - это массив объектов Mapper. Использование dry()
чтобы определить, была ли запись, была обнаружена с помощью этих методов, является неуместным. Если записи не соответствуют критериям find()
или select()
, возвращаемое значение представляет собой пустой массив.
Если вы когда-нибудь захотите выяснить, какие операторы SQL, выпущенные непосредственно вашим приложением (или косвенно через объекты Mapper), вызывают узкие места производительности, вы можете сделать это с простым:-
echo $ db -> log ();
F3 отслеживает все команды, выпущенные для базового драйвера базы данных SQL, а также время, которое необходимо для выполнения каждого оператора для завершения - просто необходимая информация, необходимая для настройки производительности приложения.
В большинстве случаев вы можете жить по удобствам, данным методами Mapper Data, которые мы обсуждали до сих пор. Если вам нужна структура, чтобы выполнить тяжелую работу, вы можете расширить Mapper SQL, объявив свои собственные классы с помощью пользовательских методов- но вы не можете избежать того, чтобы запотеть руками на каком-то хардкорном 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 ();
Расширение картинов данных таким образом-это простой способ построить модели, связанные с DB, связанные с DB.
Если вы удобны с SQL, вы, вероятно, скажете: все в ORM можно обработать с помощью SQL-запросов старой школы. Действительно. Мы можем обойтись без дополнительных слушателей событий, используя триггеры базы данных и сохраненные процедуры. Мы можем выполнить реляционные запросы с присоединенными таблицами. Орм просто ненужные накладные расходы. Но дело в том, что картины данных дают вам дополнительную функциональность использования объектов для представления сущностей базы данных. Как разработчик, вы можете писать код быстрее и быть более продуктивным. Полученная программа будет чище, если не короче. Но вам придется взвесить преимущества против компромисса в скорости - особенно при обработке больших и сложных запасов данных. Помните, что все орды - независимо от того, насколько они худы - всегда будет просто еще одним слоем абстракции. Они все еще должны передавать работу в базовые двигатели SQL.
По дизайну ORM F3 не предоставляют методы для непосредственного соединения объектов друг с другом, то есть соединение SQL - потому что это открывает банку с червями. Это делает ваше приложение более сложным, чем должно быть, и существует тенденция объектов через нетерпеливые или ленивые методы извлечения, которые должны быть запущены и даже не синхронизированы из -за наследования объекта и полиморфизма (несоответствие импеданса) с базой, которые они отобраны . Есть косвенные способы сделать это в Mapper SQL, используя виртуальные поля, но вам придется делать это программно и на свой собственный риск.
Если вы испытываете желание применить «чистые» концепции ООП в вашем приложении для представления всех ваших данных (потому что «все является объектом»), имейте в виду, что данные почти всегда живут дольше, чем приложение. Ваша программа может быть устарела задолго до того, как данные потеряли свою ценность. Не добавляйте еще один слой сложности в вашу программу, используя взаимосвязанные объекты и классы, которые слишком сильно отклоняются от схемы и физической структуры данных.
Прежде чем вы объедините несколько объектов в своем приложении, чтобы манипулировать базовыми таблицами в вашей базе данных, подумайте об этом: создание представлений для представления отношений и триггеров для определения поведения объектов в двигателе базы данных более эффективно. Реляционные двигатели базы данных предназначены для обработки просмотров, соединенных таблиц и триггеров. Они не тупые хранилища данных. Таблицы, соединенные в представлении, будут отображаться в виде одной таблицы, а без жира может быть отображение вида так же, как и обычная таблица. Репликация соединений в качестве реляционных объектов в PHP медленнее по сравнению с машинным кодом двигателя базы данных, реляционной алгеброй и логикой оптимизации. Кроме того, в нашем приложении неоднократно присоединение таблиц является верным признаком того, что дизайн базы данных необходимо проверить, и представления считаются неотъемлемой частью поиска данных. Если таблица перекрестных ссылок часто из другой таблицы часто, рассмотрите возможность нормализации ваших структур или создание представления. Затем создайте объект Mapper для автоматической карты этого представления. Это быстрее и требует меньше усилий.
Рассмотрим это представление SQL, созданное внутри вашего двигателя базы данных:-
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 ;
Ваш код приложения становится простым, потому что он не должен поддерживать два объекта Mapper (один для таблицы проектов, а другой для пользователей) просто для получения данных из двух соединенных таблиц:-
$ combined = new DB SQL Mapper ( $ db , ' combined ' );
$ combined -> load ([ ' project=? ' , 123 ]);
echo $ combined -> name ;
Совет: используйте инструменты, как они предназначены. Без жира уже имеет простой в использовании помощник SQL. Используйте его, если вам нужен больший молоток :) Попробуйте найти баланс между удобством и производительностью. SQL всегда будет вашим запасением, если вы работаете над сложными и устаревшими структурами данных.
Plug-ins are nothing more than autoloaded classes that use framework built-ins to extend F3's features and functionality. 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 );
Вот как это работает. 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. Например:-
$ db -> exec ( ' SELECT * from sizes; ' , NULL , 86400 );
If we expect the result of this database query to always be Small
, Medium
, and Large
within a 24-hour period, we specify 86400
seconds as the 2nd argument so Fat-Free doesn't have to execute the query more than once a day . Instead, the framework will store the result in the cache, retrieve it from the cache every time a request comes in during the specified 24-hour time frame, and re-execute the query when the timer lapses.
The SQL data mapper also uses the cache engine to optimize synchronization of table structures with the objects that represent them. The default is 60
seconds. If you make any changes to a table's structure in your database engine, you'll have to wait for the cache timer to expire before seeing the effect in your application. You can change this behavior by specifying a third argument to the data mapper constructor. Set it to a high value if you don't expect to make any further changes to your table structure.
$ user = new DB SQL Mapper ( $ db , ' users ' , 86400 );
By default, Fat-Free's cache engine is disabled. You can enable it and allow it to auto-detect APC, WinCache or XCache. If it cannot find an appropriate backend, F3 will use the filesystem, ie the tmp/cache/
folder:-
$ f3 -> set ( ' CACHE ' , TRUE );
Disabling the cache is as simple as:-
$ f3 -> set ( ' CACHE ' , FALSE );
If you wish to override the auto-detection feature, you can do so - as in the case of a Memcached back-end which F3 also supports:-
$ f3 -> set ( ' CACHE ' , ' memcache=localhost:11211 ' );
You can also use the cache engine to store your own variables. These variables will persist between HTTP requests and remain in cache until the engine receives instructions to delete them. To save a value in the cache:-
$ f3 -> set ( ' var ' , ' I want this value saved ' , 90 );
$f3->set()
method's third argument instructs the framework to save the variable in the cache for a 90-second duration. If your application issues a $f3->get('var')
within this period, F3 will automatically retrieve the value from cache. In like manner, $f3->clear('var')
will purge the value from both cache and RAM. If you want to determine if a variable exists in cache, `$f3->exists('var')); returns one of two possible values: FALSE if the framework variable passed does not exist in cache, or an integer representing the time the variable was saved (Un*x time in seconds, with microsecond precision).
Fat-Free also has a Javascript and CSS compressor available in the Web plug-in. It can combine all your CSS files into one stylesheet (or Javascript files into a single script) so the number of components on a Web page are decreased. Reducing the number of HTTP requests to your Web server results in faster page loading. First you need to prepare your HTML template so it can take advantage of this feature. Something like:-
< link rel =" stylesheet " type =" text/css "
href =" /minify/css?files=typo.css,grid.css " />
Do the same with your Javascript files:-
< script type =" text/javascript " src =" /minify/js?&files=underscore.js " >
</ script >
Of course we need to set up a route so your application can handle the necessary call to the Fat-Free CSS/Javascript compressor:-
$ f3 -> route ( ' GET /minify/@type ' ,
function ( $ f3 , $ args ) {
$ f3 -> set ( ' UI ' , $ args [ ' type ' ]. ' / ' );
echo Web:: instance ()-> minify ( $ _GET [ ' files ' ]);
},
3600
);
And that's all there is to it! minify()
reads each file ( typo.css
and grid.css
in our CSS example, underscore.js
in our Javascript example), strips off all unnecessary whitespaces and comments, combines all of the related items as a single Web page component, and attaches a far-future expiry date so the user's Web browser can cache the data. It's important that the PARAMS.type
variable base points to the correct path. Otherwise, the URL rewriting mechanism inside the compressor won't find the CSS/Javascript files.
In our examples, the framework sends a far-future expiry date to the client's Web browser so any request for the same CSS or Javascript block will come from the user's hard drive. On the server side, F3 will check each request and see if the CSS or Javascript blocks have already been cached. The route we specified has a cache refresh period of 3600
seconds. Additionally, if the Web browser sends an If-Modified-Since
request header and the framework sees the cache hasn't changed, F3 just sends an HTTP 304 Not Modified
response so no content is actually delivered. Without the If-Modified-Since
header, Fat-Free renders the output from the cached file if available. Otherwise, the relevant code is executed.
Tip: If you're not modifying your Javascript/CSS files frequently (as it would be if you're using a Javascript library like jQuery, MooTools, Dojo, etc.), consider adding a cache timer to the route leading to your Javascript/CSS minify handler (3rd argument of F3::route()) so Fat-Free doesn't have compress and combine these files each time such a request is received.
Want to make your site run even faster? Fat-Free works best with either Alternative PHP Cache (APC), XCache, or WinCache. These PHP extensions boost performance of your application by optimizing your PHP scripts (including the framework code).
A fast application that processes all HTTP requests and responds to them at the shortest time possible is not always a good idea - specially if your bandwidth is limited or traffic on your Web site is particularly heavy. Serving pages ASAP also makes your application vulnerable to Denial-of-Service (DOS) attacks. F3 has a bandwidth throttling feature that allows you to control how fast your Web pages are served. You can specify how much time it should take to process a request:-
$ f3 -> route ( ' /throttledpage ' , ' MyApp->handler ' , 0 , 128 );
In this example, the framework will serve the Web page at a rate of 128KiBps.
Bandwidth throttling at the application level can be particularly useful for login pages. Slow responses to dictionary attacks is a good way of mitigating this kind of security risk.
Robust applications are the result of comprehensive testing. Verifying that each part of your program conforms to the specifications and lives up to the expectations of the end-user means finding bugs and fixing them as early as possible in the application development cycle.
If you know little or nothing about unit testing methodologies, you're probably embedding pieces of code directly in your existing program to help you with debugging. That of course means you have to remove them once the program is running. Leftover code fragments, poor design and faulty implementation can creep up as bugs when you roll out your application later.
F3 makes it easy for you to debug programs - without getting in the way of your regular thought processes. The framework does not require you to build complex OOP classes, heavy test structures, and obtrusive procedures.
A unit (or test fixture) can be a function/method or a class. Let's have a simple example:-
function hello () {
return ' Hello, World ' ;
}
Save it in a file called hello.php
. Now how do we know it really runs as expected? Let's create our test procedure:-
$ f3 = require ( ' lib/base.php ' );
// Set up
$ test = new Test ;
include ( ' hello.php ' );
// This is where the tests begin
$ test -> expect (
is_callable ( ' hello ' ),
' hello() is a function '
);
// Another test
$ hello = hello ();
$ test -> expect (
! empty ( $ hello ),
' Something was returned '
);
// This test should succeed
$ test ->expect
is_string ( $ hello ),
' Return value is a string '
);
// This test is bound to fail
$ test -> expect (
strlen ( $ hello )== 13 ,
' String length is 13 '
);
// Display the results ; not MVC but let ' s keep it simple
foreach ( $ test -> results () as $ result ) {
echo $ result [ ' text ' ]. ' <br /> ' ;
if ( $ result [ ' status ' ])
echo ' Pass ' ;
else
echo ' Fail ( ' . $ result [ ' source ' ]. ' ) ' ;
echo ' <br /> ' ;
}
Save it in a file called test.php
. This way we can preserve the integrity of hello.php
.
Now here's the meat of our unit testing process.
F3's built-in Test
class keeps track of the result of each expect()
call. The output of $test->results()
is an array of arrays with the keys text
(mirroring argument 2 of expect()
), status
(boolean representing the result of a test), and source
(file name/line number of the specific test) to aid in debugging.
Fat-Free gives you the freedom to display test results in any way you want. You can have the output in plain text or even a nice-looking HTML template. So how do we run our unit test? If you saved test.php
in the document root folder, you can just open your browser and specify the address http://localhost/test.php
. Вот и все.
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. | 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]>
Эй, чувак! Help me out for a couple of !