sofadesign / limonade
一个 PHP 微型框架
This package is not auto-updated.
Last update: 2024-09-25 15:15:36 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 功能的快速、全面指南。
如需更多信息,您可以查看 网站、示例,以及当然还有源代码 lib/limonade.php,它仍然是最好的文档。
还有一个 讨论组,可用于更多交流。
要求
- 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
) 和通过选项定义的编码设置(默认为utf8)。
html('my_template.html.php');
XML模板
xml
函数与 render
的用法相同。一个标题指定了适当的HTTP Content-type
(text/xml
) 和通过选项定义的编码设置(默认为utf8)。
xml('my_template.xml.php');
CSS模板
css
函数与 render
的用法相同。一个标题指定了适当的HTTP Content-type
(text/css
) 和通过选项定义的编码设置(默认为utf8)。
css('screen.css.php');
JS模板
js
函数与 render
的用法相同。一个标题指定了适当的HTTP Content-type
(application/javascript
) 和通过选项定义的编码设置(默认为utf8)。
js('app.js.php');
TXT模板
txt
函数与 render
的用法相同。一个标题指定了适当的HTTP Content-type
(text/plain
) 和通过选项定义的编码设置(默认为utf8)。
txt('index.txt.php');
JSON模板
json
与 json_encode
函数用法相同,并返回一个包含值JSON表示的字符串。一个标题指定了适当的HTTP Content-type
(application/x-javascript
) 和通过选项定义的编码设置(默认为utf8)。
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或stylesheet文件非常有用。
例如,使用此布局
<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
函数,使其根据当前匹配的路由进行自动渲染。如果控制器返回空输出,则将执行此函数。
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()
以造成循环!
配置
你可以定义一个在应用程序启动时执行(在 run
执行的开始)的 configure
。你可以在其中定义选项,例如数据库连接...
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')
文件夹(默认为 lib/
)中的 PHP 文件在执行 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($name, $value...)
定义下一次请求的闪存- 在视图中,您可以使用
$flash
数组或flash_now($name)
函数获取当前闪存值。
⌘ 查看代码片段示例
辅助函数
有关所有可用的辅助函数的更多信息,请参阅源代码或 API。
url_for
您可以使用 url_for
函数渲染 limonade URL。无论您的应用程序安装在 Web 服务器的哪个文件夹中,它们都会从文档根目录中的任何文件夹生成。
# 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 内部服务器错误
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. 工具 部分。
测试
[待办事项]