该软件包最新版本(0.6.2)没有提供许可信息。

PHP微框架

0.6.2 2021-11-29 16:50 UTC

This package is not auto-updated.

Last update: 2024-10-02 03:55:19 UTC


README

Limo 是 Limonade 的分支。以下所有内容均适用。我们现在使用 'limo' 而不是 'limonade'。

Limonade: README

Limonade 是一个用于快速网络开发和原型设计的 PHP 微框架。

它受到 Ruby 中的框架如 SinatraCamping 的启发,或在 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

当不支持 PUTDELETEPATCH 方法(如 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函数允许传递一个变量,如果它为空,则传递一个默认值。这对于从URL中提取的可选参数的赋值非常有用,这些参数是通过params()函数提取的。

    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-typetext/html)和通过选项定义的编码设置(默认为utf8)。

    html('my_template.html.php');

模板XML

xml函数与render函数的使用方式相同。一个头部指定了正确的HTTP Content-typetext/xml)和通过选项定义的编码设置(默认为utf8)。

    xml('my_template.xml.php');

模板CSS

css函数与render函数的使用方式相同。一个头部指定了正确的HTTP Content-typetext/css)和通过选项定义的编码设置(默认为utf8)。

    css('screen.css.php');

模板JS

js函数与render函数的使用方式相同。一个头部指定了正确的HTTP Content-typeapplication/javascript)和通过选项定义的编码设置(默认为utf8)。

    js('app.js.php');

模板TXT

txt函数与render函数的使用方式相同。一个头部指定了正确的HTTP Content-typetext/plain)和通过选项定义的编码设置(默认为utf8)。

    txt('index.txt.php');

模板JSON

jsonjson_encode函数的使用方式相同,并返回一个包含值JSON表示的字符串。一个头部指定了正确的HTTP Content-typeapplication/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或样式表文件非常有用。

例如,使用此布局

    <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

您可以为每个请求定义一个将在其之前执行的 before 函数。这非常有用,可以定义默认布局或向模板传递常用变量。

    function before($route)
    {
        layout('default_layout.php');
        set('site_title', 'My Website');
    }

当前匹配的路由也会传递给 before 函数,因此您可以对其进行测试。它是一个数组,由内部 route_find 函数返回,包含以下值

  • method(HTTP 方法)
  • pattern(正则表达式模式)
  • names(参数名称)
  • callback(回调函数)
  • options(路由选项)
  • params(当前参数)

After

还有一个可用的 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

您可以为 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

您可以为 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

如果您定义了 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
    }

Before sending a header

您可以为 before_sending_header 定义一个函数,该函数将在 Limonade 调用 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(),以免造成循环!

Configuration

您可以在应用程序启动时定义一个 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') 文件夹(默认为 lib/)中的 PHP 文件将在执行 configure 之后使用 require_once 加载。因此,您可以在此文件夹中放置所有您的 PHP 库和函数,以便在应用程序启动时加载并可用。

Options

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

Sessions

默认情况下,会话会自动启动。然后您可以使用与 $_SESSION 数组相同的方式访问会话变量。

您可以使用 session 选项来禁用会话。

查看示例片段

Flash

Flash 是会话的特殊用途。Flash 值仅在下一次请求中可用,并在之后被删除。它非常适用于在表单上引发错误或通知成功操作。

  • flash($name, $value...) 为下一次请求定义一个 Flash
  • 在视图中,您可以使用 $flash 数组或 flash_now($name) 函数来获取当前的 Flash 值。

查看代码片段示例

助手函数

有关所有可用助手函数的更多信息,请参阅源代码或 API。

url_for

您可以使用 url_for 函数渲染 limonade URL。无论您的应用程序安装在 Web 服务器的哪个文件夹中,这些 URL 都将很好地形成。

    # with option('base_uri', '?')
    url_for('one', 'two', 'three'); # returns ?/one/two/three
    url_for('one', 'two', array('page' => 1)); # returns ?/one/two&amp;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_FOUNDSERVER_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. 工具 部分。

测试

[待办事项]

更多信息