codecraft63 / limonade
一个PHP微型框架
This package is not auto-updated.
Last update: 2024-09-20 19:43:46 UTC
README
Limonade 是一个用于快速网页开发和原型设计的 PHP 微型框架。
它受到了 Ruby 中的 Sinatra 或 Camping 以及 Lua 中的 Orbit 等框架的启发。它旨在简单、轻量且极具灵活性。
Limonade 提供了补充 PHP 基本集的功能,同时保持与原生函数的一致性并在此基础上扩展。
Limonade 容易学习,并提供了现代框架(MVC、REST 等)所能提供的一切。
require_once 'lib/limonade.php';
dispatch('/', 'hello');
function hello()
{
return 'Hello world!';
}
run();
关于本文档
本文档提供了 Limonade 特性的快速但全面的指南。
有关更多信息,您可以查看 网站、示例 以及当然的 源代码,这仍然是最好的文档。
还有一个 讨论组 可以用于更多交流。
要求
- PHP 5.1.6 > (已成功测试与 PHP 5.1.6 兼容,但可能也适用于旧版本)
路由
路由结合
- 一个 HTTP 方法
- 与 URL 匹配模式
- 以及回调参数
因此,它们在 URL + HTTP 方法与回调控制器中提供的代码之间起到粘合剂的作用。
dispatch('/', 'my_get_function');
# same as dispatch_get('my_get_function');
function my_get_function()
{
// Show something
// with the code of this callback controller
}
dispatch_post('/', 'my_post_function');
function my_post_function()
{
// Create something
}
dispatch_put('/', 'my_update_function');
function my_update_function()
{
// Update something
}
dispatch_delete('/', 'my_delete_function');
function my_delete_function()
{
// Delete something
}
dispatch_patch('/', 'my_patch_function');
function my_patch_function()
{
// Patch something
}
路由按声明的顺序进行匹配。搜索通过浏览器 URL 提供的路径进行
https:///my_app/?u=/my/path
https:///my_app/?uri=/my/path
https:///my_app/index.php?/my/path
https:///my_app/?/my/path
当不支持 PUT
、DELETE
或 PATCH
方法(如在 HTML 表单提交中)时,您可以在 POST
请求中使用 _method
参数:它将覆盖 POST
方法。
<form action="<?php echo url_for('profile_update'); ?>" method="post">
<p><input type="hidden" name="_method" value="PUT" id="_method"></p>
<p>... your form fields</p>
<p><input type="submit" value="Update"></p>
</form>
路由模式和参数
模式可以包含命名参数。这些参数的关联值可以通过 params()
函数获得。
dispatch('/hello/:name', 'hello');
function hello()
{
$name = params('name');
return 'Hello $name';
}
模式还可以包含通配符参数。关联值可以通过与模式相同的顺序的数字索引获得。
dispatch('/writing/*/to/*', 'my_letter');
function my_letter()
{
# Matches /writing/an_email/to/joe
$type = params(0); # "an_email"
$name = params(1); # "joe"
# ...
}
dispatch('/files/*.*', 'share_files');
function share_files()
{
# matches /files/readme.txt
$ext = params(1);
$filename = params(0).".".$ext;
# ...
}
与简单的通配符字符 *
不同,双通配符字符 **
指定可以包含 /
的字符串
dispatch('/files/**', 'share_files')
function share_files()
{
# Matches /files/my/own/file.txt
$filename = params(0); # my/own/file.txt
}
如果模式以 ^
开头,则模式也可以是正则表达式
dispatch('^/my/own/(\d+)/regexp', 'my_func');
function my_func()
{
# matches /my/own/12/regexp
$num = params(0);
}
通配符参数和正则表达式也可以命名。
dispatch(array('/say/*/to/**', array("what", "name")), 'my_func');
function my_func()
{
# Matches /say/hello/to/joe
$what = params('what');
$name = params('name');
}
您还可以提供默认参数值,这些值将与模式参数合并并由模式参数覆盖。
$options = array('params' => array('firstname'=>'bob'));
dispatch('/hello/:name', 'hello', $options);
function hello($firstname, $name) # default parameters first
{
return 'Hello $firstname $name';
}
回调控制器
回调可以是函数、对象方法、静态方法或闭包。有关回调伪类型的更多信息,请参阅 php 文档。
# will call my_hello_function() function
dispatch('/hello', 'my_hello_function');
# Static class method call, MyClass::hello();
dispatch('/hello', array('MyClass', 'hello'));
# Object method call, $obj->hello();
dispatch('/hello', array($obj, 'hello'));
# Static class method call (As of PHP 5.2.3), MyClass::hello();
dispatch('/hello', 'MyClass::hello');
# Using lambda function (As of PHP 5.3.0)
dispatch('/hello', function(){
return 'Hello World!';
});
回调控制器返回渲染的视图输出(请参阅 视图和模板)。
它们可以接受模式参数作为参数
dispatch('/hello/:firstname/:name', 'hello');
function hello($firstname, $name)
{
# $firstname parameter equals params('firstname');
# and $name parameter equals params('name');
return 'Hello $firstname $name';
}
由路由调用的回调可以在 run()
函数执行之前编写在任何地方。它们也可以分组在存储在 controllers/
文件夹中的控制器文件中。
/ # site root
- index.php # file with routes declarations and run()
+ controllers/
- blog.php # functions for blog: blog_index(), blog_show(),
# blog_post()...
- comments.php # comments_for_a_post(), comment_add()...
此文件夹位置可以通过 controllers_dir
选项进行设置。
option('controllers_dir', dirname(__FILE__).'/other/dir/for/controllers');
您还可以定义 autoload_controller
函数以自定义加载控制器
function autoload_controller($callback)
{
# If $callback, the callback function defined in matching route,
# begins with 'admin_', then we load controllers from
# the admin sub-directory in the controllers directory.
# Else we load controllers the normal way from 'controllers_dir'.
$path = option('controllers_dir');
if(strpos($callback, "admin_") === 0) $path = file_path($path, 'admin');
require_once_dir($path);
}
URL重写
从版本0.4.1开始,Limonade支持URL重写。
如果您使用Apache,在您的应用文件夹中创建一个.htaccess
文件
<IfModule mod_rewrite.c>
Options +FollowSymlinks
Options +Indexes
RewriteEngine on
# if your app is in a subfolder
# RewriteBase /my_app/
# test string is a valid files
RewriteCond %{SCRIPT_FILENAME} !-f
# test string is a valid directory
RewriteCond %{SCRIPT_FILENAME} !-d
RewriteRule ^(.*)$ index.php?uri=/$1 [NC,L,QSA]
# with QSA flag (query string append),
# forces the rewrite engine to append a query string part of the
# substitution string to the existing string, instead of replacing it.
</IfModule>
如果您使用Nginx,请将以下内容添加到您的服务器声明中
server {
location / {
try_files $uri $uri/ @rewrite;
}
location @rewrite {
rewrite ^/(.*)$ /index.php?u=$1&$args;
}
}
然后请记住在您的 configure() 函数中显式设置 option('base_uri')
option('base_uri', '/my_app'); # '/' or same as the RewriteBase in your .htaccess
您可以使用类似 http://your.new-website.com/my/limonade/path
的URL访问您的网站,而不是 http://your.new-website.com/?/my/limonade/path
。
视图和模板
模板文件默认位于 views/
文件夹中。视图文件夹的位置可以通过 views_dir
选项进行设置。
option('views_dir', dirname(__FILE__).'/other/dir/for/views');
要将变量传递给模板,我们使用 set ()
函数
set('name', 'John Doe');
render('index.html.php');
变量也可以直接传递
render('index.html.php', null, array('name' => 'John Doe' ));
set_or_default
函数允许传递一个变量,如果它为空,则传递默认值。这对于使用 params()
函数从URL中提取的可选参数的分配非常有用。
dispatch('/hello/:name', 'hello');
function hello()
{
# matching /hello/
set_or_default('name', params('name'),'John');
return render('Hello %s!'); // returns 'Hello John!' because params('name') was empty. Else it would have returned params('name') value.
}
如您所注意到的,最终输出是由您的控制器返回的。因此,请记住在控制器中显式地使用 return
关键字返回您的视图!(这对Ruby程序员特别有帮助;-)
布局
模板可以嵌入到另一个模板中:一个布局。
可以使用 layout
函数设置布局
layout('default_layout.php');
或直接使用模板渲染函数
render('index.html.php', 'default_layout.php');
如果布局值为 null
,则渲染将不使用任何布局。
render('index.html.php', null);
格式化字符串和内联模板
格式化字符串可以使用与 sprintf
相同的方式使用
set('num', 5);
set('where', 'tree');
return render('There are %d monkeys in the %s') // returns 'There are 5 monkeys in the tree'
还可以提供一个函数名作为模板。这样,例如,我们可以生成一个单文件应用程序。
function html_message($vars){ extract($vars);?>
<h1>Title: <?php echo h($title); ?></h1>
<p>Message:<br>
<?php echo h($msg); ?></p>
<?}
// in a request handling function
set('title', 'Hello!');
set('msg', 'There are 100 monkeys in the Chennai and bangalore');
return render('html_message');
HTML模板
html
函数与 render
使用方式相同。一个标题指定了正确的HTTP Content-type
(默认为 text/html
)和通过选项定义的编码设置。
html('my_template.html.php');
模板XML
xml
函数与 render
使用方式相同。一个标题指定了正确的HTTP Content-type
(默认为 text/xml
)和通过选项定义的编码设置。
xml('my_template.xml.php');
模板CSS
css
函数与 render
使用方式相同。一个标题指定了正确的HTTP Content-type
(默认为 text/css
)和通过选项定义的编码设置。
css('screen.css.php');
模板JS
js
函数与 render
使用方式相同。一个标题指定了正确的HTTP Content-type
(默认为 application/javascript
)和通过选项定义的编码设置。
js('app.js.php');
模板TXT
txt
函数与 render
使用方式相同。一个标题指定了正确的HTTP Content-type
(默认为 text/plain
)和通过选项定义的编码设置。
txt('index.txt.php');
模板JSON
json
与 json_encode
函数使用方式相同,并返回一个包含值的JSON表示的字符串。一个标题指定了正确的HTTP Content-type
(默认为 application/x-javascript
)和通过选项定义的编码设置。
json($my_data);
文件服务
render_file
函数可以直接将文件渲染到输出缓冲区。
render_file(option('public_dir').'foo.jpg');
一个标题指定了根据文件扩展名正确的HTTP Content-type
,对于文本文件,编码设置通过选项定义(默认为utf8)。
输出被缓存,以便可以轻松处理大文件。
部分
partial
函数是一个用于无布局渲染的快捷方式。对于管理可重用块并将它们保存在单独的文件中非常有用。
以下代码:
partial('my_posts.php', array('posts'=>$posts));
等同于:
render('my_posts.php', null, array('posts'=>$posts));
捕获:
content_for
函数允许您在视图中捕获一段文本。然后,捕获的块将可用于布局。这对于管理布局区域(如侧边栏)或设置针对视图特定的 JavaScript 或样式表文件非常有用。
例如,使用此布局:
<div id="content">
<div id="main">
<?php echo $content; ?>
</div>
<div id="side">
<?php if (isset($side)) echo $side; ?>
</div>
</div>
在你的视图中:
<p>My main content</p>
<?php content_for('side'); ?>
<ul>
<li><a href="<?php echo url_for('/pages/item1')?>">Item 1</a></li>
<li><a href="<?php echo url_for('/pages/item2')?>">Item 2</a></li>
</ul>
<?php end_content_for(); ?>
渲染结果是:
<div id="content">
<div id="main">
<p>My main content</p>
</div>
<div id="side">
<ul>
<li><a href="?/pages/item1">Item 1</a></li>
<li><a href="?/pages/item1">Item 2</a></li>
</ul>
</div>
</div>
上述示例在这篇教程中有详细说明。
使用捕获与部分视图一起使用,可以帮助您组织视图,并避免多次复制/粘贴相同的代码。
钩子和过滤器:
Limonade 允许用户定义一些函数来增强 Limonade 的行为以适应自己的需求。
其中一些,如 before
钩子和 after
过滤器被广泛使用,而其他一些则仅供高级使用,可能需要很好地理解 Limonade 的内部结构。
在请求之前:
您可以在每个请求之前定义一个 before
函数。这对于定义默认布局或将常用变量传递给模板非常有用。
function before($route)
{
layout('default_layout.php');
set('site_title', 'My Website');
}
当前匹配的路由也会传递给 before
函数,因此您可以对其进行测试。它是一个数组,由内部 route_find
函数返回,包含以下值:
method
(HTTP 方法)pattern
(正则表达式模式)names
(参数名称)callback
(回调函数)options
(路由选项)params
(当前参数)
在请求之后:
还提供了一个 after
输出过滤器。它在每个请求之后执行,可以对输出应用转换(除了直接发送到输出缓冲区的 render_file
输出)。
function after($output){
$config = array('indent' => TRUE,
'output-xhtml' => TRUE,
'wrap' => 200);
$encoding = strtoupper(str_replace('-','', option('encoding')));
$tidy = tidy_parse_string($output, $config, $encoding);
$tidy->cleanRepair();
return $tidy;
}
当前执行的路由也可用于 after
函数。
在渲染之前:
您可以在渲染视图之前定义一个 before_render
函数来过滤视图。
前三个参数与传递给 render
函数的参数相同:
$content_or_func
:视图字符串$layout
:当前布局路径$locals
:直接传递给render
函数的变量
最后一个参数 $view_path
默认为 file_path(option('views_dir'), $content_or_func);
function before_render($content_or_func, $layout, $locals, $view_path)
{
# Transform $content_or_func, $layout, $locals or $view_path.
# Then return there new values
return array($content_or_func, $layout, $locals, $view_path);
}
自动渲染:
您可以定义自己的 autorender
函数,根据当前匹配的路由来执行自动渲染。如果控制器返回 null 输出,则将执行该函数。
dispatch('/', 'hello');
function hello()
{
# process some stuff...
set('name', 'Bob');
# but don't return anything
# ( like if you were ending this function with return null; )
}
function autorender($route)
{
$view = $route['callback'] . ".html.php";
return html($view);
}
在下面的例子中,当调用 URL /
时,执行 hello()
,然后 autorender()
渲染匹配的 hello.html.php
视图。
在退出之前:
如果您定义了 before_exit
,则它在停止/退出过程开始时调用(Limonade 应用程序终止时自动调用 stop_and_exit
函数)。
function before_exit($exit)
{
# $exit is the same parameter as the one passed to `stop_and_exit`.
# If it's false, the exit process will not be executed,
# only the stop instructions
# by default it is true
}
在发送头信息之前:
您可以在 Limonade 发出 header() 调用之前定义一个 before_sending_header
函数。这样,您就可以添加额外的头信息。
dispatch('/style.css', 'css');
function css()
{
# Generate css file and output
return css('style.css.php');
}
function before_sending_header($header)
{
if (strpos($header, 'text/css') !== false)
{
# intercept text/css content-type and add caching to the headers
send_header("Cache-Control: max-age=600, public");
}
}
注意:小心不要从 before_sending_header
函数中重复调用 send_header()
导致循环!
配置:
您可以在应用程序启动时执行 configure
,在 run
执行的开始。您可以在其中定义选项,例如数据库连接...
function configure()
{
$env = $_SERVER['HTTP_HOST'] == "localhost" ? ENV_DEVELOPMENT : ENV_PRODUCTION;
option('env', $env);
if(option('env') > ENV_PRODUCTION)
{
options('dsn', 'sqlite:db/development.db'));
}
else
{
options('dsn', 'sqlite:db/production.db'));
}
$GLOBALS['my_db_connexion'] = new PDO(option('dsn'));
}
包含在 option('lib_dir')
文件夹中的 PHP 文件(默认为 lib/
)将在执行 configure
后通过 require_once
加载。因此,您可以在此文件夹中放置所有 PHP 库和函数,以便它们在应用程序启动时加载并可用。
选项:
option
函数允许您定义和访问应用程序的选项。
option('env', ENV_PRODUCTION);
option('env'); // return ENV_PRODUCTION value
如果没有指定选项名称,则返回所有设置的选项数组。
您可以使用它来管理Limonade选项和您自己的自定义选项。
默认的Limonade选项具有以下值
option('root_dir', $root_dir); // this folder contains your main application file
option('base_path', $base_path);
option('base_uri', $base_uri); // set it manually if you use url_rewriting
option('limonade_dir', dirname(__FILE__).'/'); // this fiolder contains the limonade.php main file
option('limonade_views_dir', dirname(__FILE__).'/limonade/views/');
option('limonade_public_dir',dirname(__FILE__).'/limonade/public/');
option('public_dir', $root_dir.'/public/');
option('views_dir', $root_dir.'/views/');
option('controllers_dir', $root_dir.'/controllers/');
option('lib_dir', $root_dir.'/lib/');
option('error_views_dir', option('limonade_views_dir'));
option('env', ENV_PRODUCTION);
option('debug', true);
option('session', LIM_SESSION_NAME); // true, false or the name of your session
option('encoding', 'utf-8');
option('x-sendfile', 0); // 0: disabled,
// X-SENDFILE: for Apache and Lighttpd v. >= 1.5,
// X-LIGHTTPD-SEND-FILE: for Apache and Lighttpd v. < 1.5
会话
默认情况下,会话会自动启动。然后您可以通过$_SESSION
数组像以前一样访问会话变量。
您可以使用session
选项禁用会话。
⌘ 查看代码片段示例
Flash
Flash是会话的特殊用途。Flash值仅在下一个请求中可用,并在之后被删除。它在表单中引发错误或通知成功操作时非常有用。
flash($name, $value...)
为下一个请求定义一个Flash- 在视图中,您可以使用
$flash
数组或flash_now($name)
函数获取当前Flash值。
⌘ 查看代码片段示例
辅助工具
有关所有可用辅助工具的更多信息,请参阅源代码或API。
url_for
您可以使用url_for
函数来渲染Limonade URL。它们将从您的应用程序安装的文档根目录中的任何文件夹生成。
# with option('base_uri', '?')
url_for('one', 'two', 'three'); # returns ?/one/two/three
url_for('one', 'two', array('page' => 1)); # returns ?/one/two&page=2
如果您想使用URL重写,则需要明确设置base_uri
选项(默认为/your_file_path/?
)
停止执行和错误处理
停止
您可以使用halt
函数立即停止应用程序的执行。错误将由默认的Limonade错误处理程序或您定义的错误处理程序处理。
halt(NOT_FOUND);
halt("En error occured in my app...");
未找到
默认情况下,显示not_found
错误输出函数并发送一个404 NOT FOUND
HTTP头。
halt(NOT_FOUND);
halt(NOT_FOUND, "This product doesn't exists.");
要为此错误定义一个新的视图,您可以简单地声明一个not_found
函数。
function not_found($errno, $errstr, $errfile=null, $errline=null)
{
set('errno', $errno);
set('errstr', $errstr);
set('errfile', $errfile);
set('errline', $errline);
return html("show_not_found_errors.html.php");
}
服务器错误
默认情况下,显示server_error
错误输出函数并发送一个500 INTERNAL SERVER ERROR
HTTP头。
halt();
halt('Breaking bad!');
halt(SERVER_ERROR, "Not good...");
trigger_error("Wrong parameter", E_USER_ERROR);
PHP错误也会被捕获并发送到此错误处理程序输出。
要为此错误定义一个新的视图,您可以简单地声明一个server_error
函数。
function server_error($errno, $errstr, $errfile=null, $errline=null)
{
$args = compact('errno', 'errstr', 'errfile', 'errline');
return html("show_server_errors.html.php", error_layout(), $args);
}
错误布局
允许您定义和访问一个专用于错误的布局。
error_layout('error_layout.php');
error_layout(); // return 'error_layout.php'
错误处理
除了常见的NOT_FOUND
和SERVER_ERROR
错误显示之外,Limonade还可以将精确的错误重定向到您自己的函数。
error(E_USER_WARNING, 'my_notices')
function my_notices($errno, $errstr, $errfile, $errline)
{
// storing php warnings in a log file
// ...
status(SERVER_ERROR);
return html('<h1>Server Error</h1>');
}
E_LIM_HTTP
表示所有HTTP错误
error(E_LIM_HTTP, 'my_http_errors')
function my_http_errors($errno, $errstr, $errfile, $errline)
{
status($errno);
return html('<h1>'.http_response_status_code($errno).'</h1>');
}
E_LIM_PHP
表示所有PHP错误(由PHP发送或由用户通过trigger_error
函数引发)。
其他有用函数
Limonade还提供了一套有用的函数,可以帮助您管理文件、HTTP等。有关这些实用工具的更多信息,请参阅源代码中的第7. 工具
部分。
测试
[待办事项]