nebiros/yasc

另一个 Sinatra 克隆

v0.1.21 2015-02-17 21:55 UTC

This package is not auto-updated.

Last update: 2024-09-28 15:59:59 UTC


README

另一个 Sinatra 克隆

yasc 是一个用 sinatra (类似) 风格编写,并深受 zend framework 1.x 影响,使用 limonade 的代码构建的路由系统,是一个小巧的框架,它使用 用户自定义 函数作为动作(类似于 MVC 模式)和 注解 将请求的 URL 路由到相应的函数。

功能

  • 基于函数。
  • RESTful。
  • 小巧 ^_^。
  • 基于正则表达式的路由系统,支持命名参数,参数对(类似于 zend framework 1.x)。
  • 视图辅助器。
  • 函数辅助器。
  • 支持布局。
  • 基于 Framework Interop Group 的类自动加载。
  • 支持模型。

默认项目结构

yasc 使用以下项目结构

app.php
views/
    helpers/
models/

如果您在项目中创建这些文件夹,它们将自动加载到您的应用程序中。默认 命名空间

helpers/Helper_*
models/Model_*

访问器

我发现调用具有许多参数的请求函数非常丑陋且有些啰嗦(只是有点?),所以我在每个函数中添加了一些 访问器 以供使用。

<?php

Yasc_App::view() // Access the view object inside your function.
Yasc_App::params() // Get all route params.
Yasc_App::params("key") // Get param "key" value, also, you can specify a default value as the second argument of this static method.
Yasc_App::config() // App config.
Yasc_App::viewHelper("url") // Get a view helper, like Layout, Url, or some of your own.
Yasc_App::functionHelper("flash") // Get a function helper, like Flash, this helper is a stack of messages, errors, notices, etc.

先决条件

yasc 需要 PHP 5.2.4 或更高版本。

安装

安装 yasc 最简单的方法是通过 composer,

php composer.phar require nebiros/yasc "~0.1.18"

或者将其作为 git submodule 添加。

创建一个 index.phpapp.php 文件并包含 yasc,如下所示

namespace My\App;

// composer autoload.
require_once "vendor/autoload.php";
// yasc runtime.
require_once "vendor/nebiros/yasc/src/Yasc.php";

$yasc = new \Yasc();
$yasc->run(__NAMESPACE__);
unset($yasc);

现在,打开您的浏览器并运行您的脚本

<?php
namespace My\App;

// composer autoload.
require_once "vendor/autoload.php";
// yasc runtime.
require_once "vendor/nebiros/yasc/src/Yasc.php";

$yasc = new \Yasc();
$yasc->run(__NAMESPACE__);
unset($yasc);

/**
 * @GET("/")
 */
function index() {
    echo "Hello world!";
}

按照示例操作,您就完成了 :).

https:///app.php

按照示例操作,您就完成了 :).

设置

也许您希望 隐藏 脚本文件从 URL 中,例如 http://app.com/app.php/some/thing(我知道,漂亮的结构化 URL,SEO 关闭,等等)并获取更酷的东西,例如: http://app.com/some/thing,好吧,创建一个 虚拟主机 并在您的应用程序文件夹中添加一个 .htaccess 文件,如下所示

虚拟主机配置

<VirtualHost *:80>
   DocumentRoot "/path/to/your/application/public"
   ServerName app.com
   <Directory "/path/to/your/application/public">
       Options -Indexes MultiViews FollowSymLinks
       AllowOverride All 
       Order allow,deny
       Allow from all 
   </Directory>
</VirtualHost>

.htaccess 文件

RewriteEngine On
RewriteCond %{REQUEST_FILENAME} -s [OR]
RewriteCond %{REQUEST_FILENAME} -l [OR]
RewriteCond %{REQUEST_FILENAME} -d
RewriteRule ^.*$ - [NC,L]
RewriteRule ^.*$ index.php [NC,L]

注意:您的应用程序文件必须命名为 index.php 才能与该 .htaccess 文件一起工作。

简单示例

<?php
namespace My\App;

// composer autoload.
require_once "vendor/autoload.php";
// yasc runtime.
require_once "vendor/nebiros/yasc/src/Yasc.php";

$yasc = new \Yasc();
$yasc->run(__NAMESPACE__);
unset($yasc);

/**
 * @GET("/")
 */
function index() {
    echo "Hello world!";
}

/**
 * @POST("/")
 */
function create() {
    // save something.
}

/**
 * @PUT("/")
 */
function update() {
    // update something.
}

/**
 * @DELETE("/")
 */
function destroy() {
    // delete something.
}

配置

<?php

/**
 * Function to configure some yasc options. This function is optional you don't
 * need to write it in your app script if you don't want.
 */
function configure() {
    // * You can add a layout, a layout is just a .phtml file that represents
    // the site template.
    Yasc_App::config()->setLayoutScript(dirname(__FILE__) . "/layouts/default.phtml");
    
    // * If you want to use a stream wrapper to convert markup of mostly-PHP 
    // templates into PHP prior to include(), seems like is a little bit slow,
    // so by default is off.
    // ->setViewStream(true);
    // 
    // * You can add more than one folder to store views, each view script
    // is a .phtml file.
    // ->addViewsPath(dirname(__FILE__) . "/extra_views");
    // 
    // * You can add more than one path of view helpers and set a
    // class prefix for the path added.
    // ->addViewHelpersPath(dirname(__FILE__) . "/../library/My/View/Helper", "My_View_Helper");
    // 
    // or if you don't want a class prefix just leave it blank.
    // ->addViewHelpersPath(dirname(__FILE__) . "/extra_views/helpers");
    //
    // * Function helpers, second argument is a prefix class.
    // ->addFunctionHelpersPath(dirname(__FILE__) . "/extra_function_helpers");
    // 
    // * Add models folder, second argument is a prefix class.
    // ->addModelsPath(dirname(__FILE__) . "/models");
    // ->addModelsPath(dirname(__FILE__) . "/extra_models/My/Model", "My_Model");
    // 
    // * Add extra options to the configuration object, like some $mysql connection 
    // resource or a global flag, etc.
    // ->addOption("db", $mysql);
}

预和后分发钩子

我们提供了两个函数,pre_dispatchpost_dispatch,可以在调用动作之前和之后调用。

高级示例

<?php

/**
 * @GET("/")
 */
function index() {
    // Use layout view helper to disable the layout or use Yasc_Layout object
    // Yasc_Layout::getInstance()->disable(), Yasc_Layout uses singleton pattern.    
    Yasc_App::view()->layout()->disable();
    
    // Get the mysql resource from this app configuration option.
    // 
    // $mysql = Yasc_App::config()->getOption("db");
    // 
    // ... do some sql operation.
    
    echo "Hello world!";
}

/**
 * @POST("/")
 * 
 * You can route the same url to another function using a different request
 * method.
 */
function save_index() {
    Yasc_App::view()->layout()->disable();
    
    echo "<pre>";
    echo "post: ";
    var_dump($_POST);
    echo "</pre>";
}

/**
 * @GET("/tales")
 */
function tales() {    
    // You can add variables to the view object and get his value on
    // the view script using the variable $this, like: $this->tales.
    Yasc_App::view()->tales = "oh! I'm a view variable!";

    // Render a view script, a view script is a .phtml file where you can mix
    // php and html, the V in the MVC model, in this example the view files
    // are stored in views/ folder.
    // 
    // This view calls a view helper 'Tales', so check views/helpers/Tales.php 
    // to see what it does.
    Yasc_App::view()->render("tales");
}

/**
 * @GET("/tales/:lol")
 * @POST("/woot") // Ignored, yasc only uses the first annotation found.
 * 
 * Named params, you can access those via Yasc_App::params() method.
 * 
 * Matches: /tales/foo and /tales/bar
 */
function tales1() {
    Yasc_App::view()->layout()->disable();
    
    echo "<pre>";
    echo "lol value: " . Yasc_App::params("lol");
    echo "</pre>";
    Yasc_App::view()->tales = "oh! I'm a view variable!";
    
    // instance of a model.
    $foo = new Model_Foo();
    Yasc_App::view()->helloModel = $foo->doSomething();
    
    // Render a view without the layout.
    Yasc_App::view()->render("tales");
}

/**
 * @GET("/tales/:lol/id/:id")
 */
function tales2() {
    Yasc_App::view()->layout()->disable();
    
    echo "<pre>";
    echo "lol value: " . Yasc_App::params("lol");
    echo "id value: " . Yasc_App::params("id");
    echo "</pre>";
}

/**
 * @POST("/tales3")
 */
function tales3() {
    Yasc_App::view()->layout()->disable();
    
    echo "<pre>";
    echo "post: ";
    var_dump($_POST);
    echo "</pre>";
}

/**
 * @GET("/foo")
 */
function foo() {
    // Render view script foo, this view script calls the view helper class 'Foo',
    // this view helper render a view helper script inside and return his content
    // to this view, a view helper script is just another .phtml file, if you don't
    // want to create a whole html string inside the helper ;).
    Yasc_App::view()->render("foo");
}

/**
 * @GET("^/regex/id/(\d+)/name/([a-z]+)")
 * 
 * You can create patterns using a regular expression, this kind of route must
 * begin with a '^'. Check limonade docs and code if you want more information, or
 * just use limonade framework :), it's a more robust framework.
 * 
 * http://www.limonade-php.net/README.htm
 * https://github.com/sofadesign/limonade/blob/master/lib/limonade.php
 * 
 * Matches: /regex/id/26/name/juan
 */
function regex() {
    Yasc_App::view()->layout()->disable();
    
    echo "<pre>";
    echo "params: ";
    var_dump(Yasc_App::params());
    echo "</pre>";
}

/**
 * @GET("/say/*\/to\/*")
 * 
 * Patterns may also include wildcard parameters. Each value is associted 
 * through numeric indexes, in the same order as in the pattern.
 * 
 * Matches: /say/hello/to/world
 */
function single_asterisk() {
    Yasc_App::view()->layout()->disable();
    
    echo "<pre>";
    echo "params: ";
    var_dump(Yasc_App::params());
    echo "hello: ";
    var_dump(Yasc_App::params(0)); // hello
    echo "world: ";
    var_dump(Yasc_App::params(1)); // world
    echo "</pre>";    
}

/**
 * @GET("/download/*.*")
 * 
 * Matches: /download/file.xml
 */
function download() {
    Yasc_App::view()->layout()->disable();
    
    echo "<pre>";
    echo "params: ";
    var_dump(Yasc_App::params());
    echo "filename: ";
    var_dump(Yasc_App::params(0)); // file
    echo "ext: ";
    var_dump(Yasc_App::params(1)); // xml
    echo "</pre>";    
}

/**
 * @GET("/writing/*\/to\/**")
 * 
 * The double wildcard '**' matches a string like this one: my/friend/juan/badass,
 * this string is treated as pairs, this way: param1/value1/param2/value2 etc, like
 * Zend Framework does, so, via Yasc_App::params() method you can get those 
 * values using each key.
 * 
 * Matches: /writing/hello/to/my/friends/from/limonade/you_guys/roxor
 */
function pairs() {
    Yasc_App::view()->layout()->disable();
    
    echo "<pre>";
    echo "params: ";
    var_dump(Yasc_App::params());
    echo "single wildcard: ";
    var_dump(Yasc_App::params(0)); // hello
    echo "param my: ";
    var_dump(Yasc_App::params("my")); // friend
    echo "param from: ";
    var_dump(Yasc_App::params("from")); // limonade
    echo "param you_guys: ";
    var_dump(Yasc_App::params("you_guys")); // roxor
    echo "</pre>";    
}

/**
 * @GET("/update")
 */
function update() {
    /* @var $flash Yasc_Function_Helper_Flash */
    $flash = Yasc_App::functionHelper("flash");
    Yasc_App::view()->flash = $flash;
    
    return Yasc_App::view()->render("update");    
    
    // Use '_method' parameter in POST requests when PUT or DELETE methods 
    // are not supported.
    
    /*
    <form id="put" name="put" action="<?php echo $this->url(array("uri" => "/update")) ?>" method="post">
        <p>First name: <input type="text" name="first_name" /></p>
        <p>Last name: <input type="text" name="last_name" /></p>
        <p><input type="submit" value="Update" /></p>
        <input type="hidden" name="_method" value="PUT" id="_method" />
    </form>
    */
}

/**
 * @PUT("/update")
 */
function save_update() {
    Yasc_App::view()->layout()->disable();
    
    // $mysql = Yasc_App::config()->getOption("db");
    // $mysql->update("table1", array("first_name" => $_POST["first_name"], "last_name" => $_POST["last_name"]));
    
    /* @var $flash Yasc_Function_Helper_Flash */
    $flash = Yasc_App::functionHelper("flash");
    $flash->message("Done.");
    
    header("Location: " . Yasc_App::viewHelper("url")->url(array("uri" => "/update")));
}

/**
 * @DELETE("/delete")
 */
function destroy() {
    Yasc_App::view()->layout()->disable();
    
    // $mysql = Yasc_App::config()->getOption("db");
    // $mysql->delete("table1", "id = {$_POST["id"]}");
    
    header("Location: " . Yasc_App::viewHelper("url")->url(array("uri" => "/update")));
}

待办事项

  • 支持 PUT 和 DELETE 方法。
  • 支持注解中的正则表达式。
  • 添加 PUT 和 DELETE 注解。
  • 添加布局支持。
  • 添加视图辅助器支持。
  • 缓存。
  • 测试。
  • 改进文档。