该包已被废弃且不再维护。作者建议使用 silex/silex 包。

辣椒应用程序工具包。

dev-master 2014-11-13 18:25 UTC

This package is not auto-updated.

Last update: 2022-02-01 12:41:30 UTC


README

辣椒是一个小巧但充满活力的应用程序工具包,旨在帮助您轻松构建出色的RESTful Web应用程序。

辣椒 处于积极开发中, (见以下说明) 提供您所需的一切,但无需多余,易于初学者和专业人士使用。您只需要一个运行PHP >=5.3的Web服务器,如Apache或nginx。您一定会喜欢它。

弃用 (* 2012† 2014)

请注意,自2014年以来,辣椒已被废弃且不再维护。此存储库保留是为了提供维护现有辣椒项目所需的必要文档。如果您正在寻找辣椒的替代方案,您应该查看出色的 Silex 微框架 和所有精彩的 Symfony 组件

另一个PHP工具包?

我制作了辣椒,因为我想帮助优秀的人创造出色的事物。除此之外,这就是我尽可能多地致力于辣椒的原因。它最初是一个资源,用于帮助在 fapprik 上创建更美观、更易用的内部工具。在整个开发过程中,我知道其他人也可以用它来做酷的事情。由于我是开源工具的巨大支持者,我想用这个工具回馈社区。

入门

下载辣椒

首先,您需要 下载 当前版本的辣椒并将其解压缩到您的虚拟主机的公共目录中。

设置您的Web服务器

为了拥有像 http://example.com/about 这样的美丽URL,辣椒需要您进行一些小的服务器配置——这非常简单,您可以在下面找到所需的一切。

Apache

如果您在Apache Web服务器上运行辣椒,请检查您的托管提供商是否启用了 mod_rewrite 模块(现在通常已启用)。如果已启用,您需要在辣椒安装的根目录中创建一个 .htaccess 文件(如果尚不存在),并将以下重写规则添加到其中。

RewriteEngine on
RewriteBase /
RewriteCond %{REQUEST_FILENAME} !-f
RewriteCond %{REQUEST_FILENAME} !-d
RewriteRule . /index.php [L]

nginx

如果您在nginx Web服务器上运行辣椒,您需要将以下重写规则添加到您的站点配置中。

location / {

    root /path/to/papprika;
    index index.php;

    if (!-f $request_filename) {
        rewrite ^(.*)$ /index.php last;
        break;
    }

    if (!-d $request_filename) {
        rewrite ^(.*)$ /index.php last;
        break;
    }

}

辣椒应用程序

要开始使用papprika,你只需要 require papprika.php 文件并创建一个 papprika\Application 的实例。在你的控制器定义之后,调用你的应用程序的 run 方法。

require_once './papprika.php';

$app = new papprika\Application();

// your controller-definitions

$app->run();

子目录

当然,papprika 也可以在子目录中使用。只需通过构造函数传递子目录路径(不带尾随斜杠)。

$app = new papprika\Application('/sub/directory');

路由

使用papprika,您必须定义路由和相应的控制器,当路由匹配时将调用这些控制器。在每条路由的开始处,您必须选择适当的方法(GETPOSTPUTDELETE),它描述了与资源的交互。如果您无法决定选择哪个方法,您可以使用 $app->any('/home', …) 来使用所有四种方法。每个路由有一个或多个模式,定义指向您的资源的路径,并且可以包含您能够捕获和处理的变量。如果想要为路由使用多个模式,只需传递一个数组而不是字符串。最后但同样重要的是,您必须使用闭包或方法(有关更多信息,请参阅「扩展papprika」)提供您的控制器。

$app->get('/home', function() {
    // do something
});

这很简单,对吧?别担心,剩下的同样简单。让我们看一个更详细的示例,它展示了闭包的优点——可以从其定义外部导入内容的匿名函数。这与全局变量不同,因为外部状态不一定是全局的。

$news = array(
    1 => array(
        'date' => '2010-01-01',
        'author' => 'thomas',
        'title' => 'Hello World!',
        'text' => 'Hello World!'
    ),
    2 => array(
        'date' => '2011-01-01',
        'author' => 'thomas',
        'title' => 'papprika 0.1 released',
        'text' => 'Hello World!'
    ),
    3 => array(
        'date' => '2012-01-01',
        'author' => 'thomas',
        'title' => 'papprika 0.2 released',
        'text' => 'Hello World!'
    )
);

$app->get('/news', function() use ($news) {
    echo '<ul>';
    foreach($news as $id => $post) {
        echo '<li><a href="/news/'.$id.'">'.$post['title'].'</a></li>';
    }
    echo '</ul>';
});

访问 /news 将返回新闻列表。use-语句告诉闭包从外部作用域导入 $news-变量,这允许我们在闭包中使用它。

动态路由

现在我们需要另一个控制器来查看单个新闻,这是通过动态路由实现的。

$app->get('/news/:id', function($id) use ($news) {
    if(!array_key_exists($id, $news)) {
        die('Post #'.$id.' wasn\'t found…');
    }
}, function($id) use ($news) {
    echo '<h1>'.$news[$id]['title'].'</h1>';
    echo '<h2>'.$news[$id]['date'].'</h2>';
    echo nl2br($news[$id]['text']);
});

您注意到两个变化吗?一方面,我们将 :id 添加到模式中,这导致该路由定义有一个名为 id 的变量,它传递给闭包。当然,您可以使用尽可能多的这些变量。另一方面,我们在本例中使用了两个控制器来处理模式。您可以为这些中间回调提供无限数量的这些,这些回调必须是可调用的闭包或方法,并且将按照指定的顺序调用。这没有更大的原因,但允许您分离代码(首先检查传递的ID是否存在,然后显示它)。

如您所知,现在您已经了解了获取页面的所有内容,现在是时候创建第一条路由了:一个联系表单,我们将使用 mail-函数来发送电子邮件。

$app->post('/contact', function() use ($app) {
    $message = $app->request('message');
    mail('&#112;&#097;&#112;&#112;&#114;&#105;&#107;&#097;&#064;&#116;&#104;&#111;&#109;&#097;&#115;&#114;&#097;&#115;&#115;&#104;&#111;&#102;&#101;&#114;&#046;&#099;&#111;&#109;', 'Contact', $message);
});

papprika为您提供了一个简单的方法来根据请求方法检索传输的变量。在上面的示例中,$app->request('message') 返回 $_POST['message']。这适用于所有方法。

从配置文件添加路由

有时将您的路由从 index.php 中分离出来可能是有意义的——例如,如果您希望使 index.php 可重用且独立于应用程序的路由。因此,您可以从配置文件(INI文件)中添加路由。

$app->ini('./routing.ini');
[get]
/contact = Thomas\TestApp\Controller\ContactController::indexAction

[post]
/contact = Thomas\TestApp\Controller\ContactController::sendAction

如您所注意到的,您必须使用方法来定义路由的回调。有关更多信息,请参阅「扩展papprika」。

出于安全原因,您应该通过您的web服务器拒绝对该配置文件的任何访问。

条件

在某些情况下,您可能只想匹配某些表达式——因此papprika允许您通过在由路由方法返回的控制器对象上调用assert来使用正则表达式定义条件。

$app->get('/news/:id', function($id) use ($news) {
    // do something
})->assert('id', '\d+');```

```php
$app->get('/hello/:name', function($name) {
    echo 'Hello, '.$name;
})->assert('name', '([a-zA-Z]+)');

上面的示例确保id参数是数字的,因为\d+是一个匹配任意数量数字的正则表达式。

before / after / error

papprika允许您在每次请求之前和之后,或者在请求的页面未找到时运行代码。您只需传递闭包/方法即可。

$app->before(function() {
    echo '<!DOCTYPE html>';
    echo '<html>';
        echo '<head>';
            echo '<meta charset="utf-8">';
        echo '</head>';
        echo '<body>';
            echo '<header>Test-Application</header>';
})->after(function() {
            echo '<footer>© papprika</footer>';
        echo '</body>';
    echo '</html>';
})->error(function() {
    echo 'The page you requested couldn’t be found.';
});

如您所见,beforeafter对于某些头部/页脚内容来说非常漂亮。您注意到上面的示例中的路由是链式调用的吗?这有点像jQuery,非常适合组织/分组您的路由。

$app->get(array('/', '/news'), function() use ($news) {
    // do something
})->get('/news/:id/:title', function($id, $title) use ($news) {
    // do something with $id and $title
});

papprika\Templates

尽管有几个模板系统可用,但它们的方法都没有真正令人满意。其中许多使用它们自己的伪语法,这使得事情变得更复杂而不是简化整个模板问题。因此,papprika带来了自己的小型模板系统,它易于理解和使用。这在布局和逻辑分离方面可能有点危险,需要特别注意,但您将得到非常快速的实施和高可变的应用。因此,请始终仔细考虑函数应该放在哪里。

因为三行代码胜过千言万语,让我们看看在papprika应用程序中使用模板有多容易!

echo new papprika\Template('./footer.php', array(
    'copyright' => 2011-'.date('Y')
));

哇,这真快,而且没有痛苦,对吧?让我们看一下footer.php文件...

        echo '<footer>© '.$this->copyright.' papprika</footer>';
    echo '</body>';
echo '</html>';

就是这样。

自定义 / beforeParse / afterParse

如果您需要/想要,您可以自定义该类。此外,还有两个名为beforeParseafterParse的方法,它们在模板解析并填充您的内容之前和之后执行。它们也需要一些自定义。想要一个例子吗?

class tpl extends papprika\Template {

    public function __construct($file, $data = array()) {
        parent::__construct('/var/www/templates/'.$file, $data);
    }

    function afterParse() {
        $this->_output = str_replace('HTML', '<abbr title="Hypertext Markup Language">HTML</abbr>', $this->_output);
    }

}

papprika\File

papprika还为您提供了在应用程序中处理文件的一些有用且方便的函数。

方法 描述
$file->name() 返回文件名(不带扩展名)
$file->filename() 返回文件的完整名称
$file->extension() 返回文件扩展名
$file->modified() 返回文件的最后修改日期(Unix时间戳)
$file->size() 返回原始文件大小(字节)
$file->niceSize() 返回可读的文件大小(KB,MB,…)
$latest = new papprika\File('./latest.zip');
echo '<a href="latest.zip">Download <em>'.$latest->name().'</em>.'.$latest->extension().' ('.$latest->niceSize().')</a>';

顺便说一句:对于图像,每个文件都有进一步的信息提供。

方法 描述
$file->width() 返回图像的宽度
$file->height() 返回图像的高度
$file->mime() 返回图像的MIME类型
$team = new papprika\File('./team.jpg');
echo '<img src="team.jpg" alt="" width="'.$team->width().'"> height="'.$team->height().'">';

遗憾的是,papprika还没有内置图像调整大小功能,但它提供了一些有用的函数来重新计算您图像的大小。当然,您不会得到更小的文件,但您可以将图像以不同的尺寸嵌入到您的应用程序中。

$logo = new papprika\File('./logo.jpg')->max(200);
echo '<img src="logo.jpg" alt="" width="'.$logo->width().'" height="'.$logo->height().'">';
$logo = new papprika\File('./logo.jpg')->maxWidth(200);
echo '<img src="logo.jpg" alt="" width="'.$logo->width().'" height="'.$logo->height().'">';
$logo = new papprika\File('./logo.jpg')->maxHeight(200);
echo '<img src="logo.jpg" alt="" width="'.$logo->width().'" height="'.$logo->height().'">';

papprika\MySQL\Connection

papprika为您提供了在应用程序中使用MySQL数据库的简单方法。首先,您使用主机、用户名和密码连接到数据库,并选择数据库。

$db = new papprika\MySQL\Connection('localhost', 'root', '123', 'app');

字符集

您也可以轻松设置适当连接的默认字符集。

$db->charset('utf8');

papprika\MySQL\Queries

由于我们已经建立了连接,我们可以开始执行一些查询并获取结果行,这些结果以对象的形式返回。

$res = new papprika\MySQL\Query('SELECT * FROM news', $db);
echo '<ul>';
while($post = $res->fetch()) {
    echo '<li><a href="/news/'.$post->id.'">'.$post->title.'</a></li>';
}
echo '</ul>';

除了 fetch 方法外,还有三种其他方法可能对您的日常数据库业务也很有用。

获取行

rows 方法从适当的结果集中检索行数。此命令仅对返回实际结果集的 SELECTSHOW 语句有效。

$res = new papprika\MySQL\Query('SELECT * FROM news', $db);
echo $res->rows().' news found.';

受影响行

要检索受 INSERTUPDATEREPLACEDELETE 查询影响的行数,affected 方法是您的得力助手。

$res = new papprika\MySQL\Query('UPDATE news SET title = "abc"', $db);
echo $res->affected().' news were affected.';

插入的 ID

最后但同样重要的是,您可能希望检索由适当的查询生成的 AUTO_INCREMENT 列的 ID。

$res = new papprika\MySQL\Query('INSERT INTO news (title) VALUES ("Hello World")', $db);
$newsId = $res->id();

转义

众所周知,周围有几个人试图对您的应用程序进行一些 SQL 注入。Papprika 就像您一样讨厌这些人,因此它提供了一个非常简单的语法来构建查询,同时准备和转义一切以防止注入。让我们来看一个例子。

$a = $app->request('a');
$b = $app->request('b');
$query = 'SELECT * FROM news WHERE a = "%s" && b = "%s"';
$res = new papprika\MySQL\Query($query, $a, $b, $db);

$a$b 将自动转义并插入到 %s 占位符中。用法等同于 sprintf

只有 MySQL?:(

如您所注意到的,我们将 MySQL 相关内容放入了其自己的子命名空间(papprika\MySQL)。那么,猜猜看!未来对其他数据库扩展的实施也已计划!:)

扩展 Papprika

当使用 Papprika 在大型项目中工作时,您可能有 20-30 个长的内联控制器,一切都会变得有些混乱。我听到的常见抱怨之一是 papprika 强迫您将所有代码放入单个文件中。但您不必这样做,相反,我强烈建议将您的控制器移动到类中。

namespace Thomas\TestApp\Controller;

class ChatController {

    public function messageAction($id) {
        …
    }

}
$app->get('/chat/message/:id', 'Thomas\TestApp\Controller\ChatController::messageAction');

如果类名太长,您可以轻松编写一个花哨的函数来缩短它们。

function controller($name) {
    list($class, $method) = explode('/', $name, 2);
    return sprintf('Thomas\TestApp\Controller\%sController::%sAction', ucfirst($class), $method);
}

$app->get('/chat/message/:id', controller('chat/message'));

因此,如您所希望看到的,Papprika 能够随着代码库的增长而有机地扩展。

Papprika 与框架对比

在 Papprika 和其庞大的兄弟之间划一条界限很困难。Papprika 不是框架,但它为您提供了构建自己框架所需的一切。如果您对做出所有自己的架构决策感到舒适,请使用 Papprika;如果不舒服,请使用完整的全栈框架。换句话说:您的应用程序有多大,有多少路由、控制器和服务,这并不重要。您将在技术层面上找到解决方案。您实际上将面临的挑战是人员。

完整示例

以下示例展示了上述提到的几个事物的组合。

$app = new papprika\Application();

$app->before(function() {
    echo new papprika\Template('./header.php', array(
        'title' => 'News @ '.$_SERVER['HTTP_HOST'],
        'time' => time()
    ));
})->after(function() {
    echo new papprika\Template('./footer.php', array(
        'copyright' => '2011-'.date('Y')
    ));
})->error(function() {
    echo new papprika\Template('./404.php');
});

$db = new papprika\MySQL\Connection('localhost', 'root', '123', 'app');
$db->charset('utf8');

$app->get('/news', function() use ($db) {
    $news = new papprika\MySQL\Query('SELECT * FROM news', $db);
    echo '<ul>';
    while($post = $news->fetch()) {
        echo '<li><a href="/news/'.$post->id.'">'.$post->title.'</a></li>';
    }
    echo '</ul>';
});

$app->get('/news/:id', function($id) use ($db, $templates) {
    $query = 'SELECT title, text, date FROM news WHERE id = "'.$id.'"';
    $res = new papprika\MySQL\Query($query, $db);
    if($res->rows() == 0) {
        echo 'FOUR OH FOUR';
    } else {
        $post = $res->fetch();
        echo new papprika\Template('./post.php', array(
            'title' => $post->title,
            'text' => nl2br($post->text),
            'date' => date('F jS Y', $post->date)
        ));
    }
})->assert('id', '\d+');

$app->get('/search', function() use ($db, $app) {
    $q = $app->request('q');
    $query = 'SELECT title, text, date FROM news WHERE title = "%s"';
    $res = new papprika\MySQL\Query($query, $q, $db);
    if($res->rows() == 0) {
        echo 'Nothing found…';
    } else {
        echo '<ul>';
        while($post = $res->fetch()) {
            echo '<li><a href="/news/'.$post->id.'">'.$post->title.'</a></li>';
        }
        echo '</ul>';
    }
});

$app->run();

许可

版权所有 (c) 2012-2014 托马斯·拉斯霍弗
许可协议:MIT。

有关更多信息,请参阅 LICENSE。