教科書般的PHP框架學習指南php
注:翻譯水平有限,若有錯誤,歡迎指正css
If you’re looking for a tour through all the ingredients for setting up a very simple Slim application (this one doesn’t use Twig, but does use Monolog and a PDO database connection) then you’re in the right place. Either walk through the tutorial to build the example application, or adapt each step for your own needs.html
若是您正在尋找創建一個很是簡單的Slim應用程序所需的要素(這個應用程序不使用Twig,可是使用了Mongolog和PDO數據庫鏈接),那麼您來對地方了。您能夠跟着本教程來構建示例應用程序,也能夠根據本身的須要調整每一個步驟。前端
Before you start: There is also a skeleton project which will give you a quick-start for a sample application, so use that if you’d rather just have something working rather than exploring how all the moving parts work.mysql
在開始以前:還有一個骨架項目,它將爲示例應用程序提供一個快速啓動,所以,若是您只想讓某些東西工做,而不想探究全部移動部件是如何工做的,那麼可使用它。nginx
Start by making a folder for your project (mine is called project, because naming things is hard). I like to reserve the top level for things-that-are-not-code and then have a folder for source code, and a folder inside that which is my webroot, so my initial structure looks like this:git
首先爲您的項目建立一個文件夾(個人文件夾名爲project,由於命名很困難)。我喜歡把非代碼的東西放在頂層,而後一個文件夾用來放源碼,另外一個文件夾用來作webroot,因此個人初始結構是這樣的:web
.
├── project
│ └── src
│ └── public
複製代碼
Composer is the best way to install Slim Framework. If you don’t have it already, you can follow the installation instructions, in my project I’ve just downloaded the composer.phar into my src/ directory and I’ll use it locally. So my first command looks like this (I’m in the src/ directory):sql
Composer是安裝Slim框架的最佳方法。若是你尚未,你能夠按照說明安裝,在個人項目中,我剛剛下載了composer.phar到個人src/目錄中,我將在本地使用它。因此個人第一個命令是這樣的(我在src/目錄中):數據庫
php composer.phar require slim/slim
複製代碼
This does two things:
Add the Slim Framework dependency to composer.json (in my case it creates the file for me as I don’t already have one, it’s safe to run this if you do already have a composer.json file)
向composer.json添加slim依賴(在個人例子中,它爲我建立了一個文件,由於我尚未一個,若是您已經有一個composer.json,那麼運行這個文件也是安全的)
Run composer install so that those dependencies are actually available to use in your application
運行composer install,以便這些依賴項實際上能夠在應用程序中使用
If you look inside the project directory now, you’ll see that you have a vendor/ folder with all the library code in it. There are also two new files: composer.json and composer.lock. This would be a great time to get our source control setup correct as well: when working with composer, we always exclude the vendor/ directory, but both composer.json and composer.lock should be included under source control. Since I’m using composer.phar in this directory I’m going to include it in my repo as well; you could equally install the composer command on all the systems that need it.
若是您如今查看項目目錄,您將看到您有一個包含全部庫代碼的vendor/文件夾。還有兩個新文件:composer.json和composer.lock。這將是糾正源代碼控制設置的好時機:當使用composer時,咱們老是排除vendor/目錄,但把composer.json和composer.lock放在源代碼控制之下。由於我用的composer.phar在當前這個目錄中,我也將把它包含在個人代碼庫中;您一樣也能夠在全部須要composer命令的系統上全局安裝composer命令並使用它。
To set up the git ignore correctly, create a file called src/.gitignore and add the following single line to the file:
要正確設置git ignore,請建立一個名爲src/.gitignore的文件。並在文件中添加如下單行:
vendor/*
複製代碼
Now git won’t prompt you to add the files in vendor/ to the repository - we don’t want to do this because we’re letting composer manage these dependencies rather than including them in our source control repository.
如今git不會提示您將vendor/中的文件添加到存儲庫中——咱們不想這樣作,由於咱們讓composer管理這些依賴項,而不是將它們包含在咱們的源代碼控制存儲庫中。
There’s a really excellent and minimal example of an index.php for Slim Framework on the project homepage so we’ll use that as our starting point. Put the following code into src/public/index.php:
在項目主頁上有一個很好的例子,它是index.php for Slim框架的一個很是小的例子,因此咱們將使用它做爲咱們的起點。將如下代碼放入src/public/index.php:
<?php
use \Psr\Http\Message\ServerRequestInterface as Request;
use \Psr\Http\Message\ResponseInterface as Response;
require '../../vendor/autoload.php';
$app = new \Slim\App;
$app->get('/hello/{name}', function (Request $request, Response $response, array $args) {
$name = $args['name'];
$response->getBody()->write("Hello, $name");
return $response;
});
$app->run();
複製代碼
We just pasted a load of code … let’s take a look at what it does.
咱們剛剛粘貼了一大堆代碼…讓咱們看看它是作什麼的。
The use statements at the top of the script are just bringing the Request and Response classes into our script so we don’t have to refer to them by their long-winded names. Slim framework supports PSR-7 which is the PHP standard for HTTP messaging, so you’ll notice as you build your application that the Request and Response objects are something you see often. This is a modern and excellent approach to writing web applications.
腳本頂部的use語句只是將請求和響應類引入到腳本中,所以咱們沒必要經過它們冗長的名稱引用它們。Slim框架支持PSR-7,這是HTTP消息傳遞的PHP標準,所以在構建應用程序時,您將注意到請求和響應對象是您常常看到的對象。這是編寫web應用程序的一種現代而優秀的方法。
Next we include the vendor/autoload.php file - this is created by Composer and allows us to refer to the Slim and other related dependencies we installed earlier. Look out that if you’re using the same file structure as me then the vendor/ directory is one level up from your index.php and you may need to adjust the path as I did above.
接下來,咱們將包含vendor/autoload.php文件——該文件由Composer建立,容許咱們引用前面安裝的Slim和其餘相關依賴項。注意,若是您使用的是與我相同的文件結構,那麼vendor/目錄比index.php高一級,您可能須要像我上面所作的那樣調整路徑。
Finally we create the app->get() call is our first 「route」 - when we make a GET request to /hello/someone then this is the code that will respond to it. Don’t forget you need that final $app->run() line to tell Slim that we’re done configuring and it’s time to get on with the main event.
最後,咱們建立app->get()調用是咱們的第一個「路由」——當咱們向/hello/somename發出get請求時,這是響應它的代碼。不要忘記,您須要最後的$app->run()行來告訴Slim咱們已經完成了配置,如今是繼續處理主事件的時候了。
Now we have an application, we’ll need to run it. I’ll cover two options: the built-in PHP webserver, and an Apache virtual host setup.
如今咱們有了一個應用程序,咱們須要運行它。我將介紹兩個選項:內置的PHP web服務器和Apache虛擬主機設置。
This is my preferred 「quick start」 option because it doesn’t rely on anything else! From the src/public directory run the command:
這是我首選的「快速啓動」選項,由於它不依賴於任何其餘東西!從src/public目錄運行命令:
php -S localhost:8080
複製代碼
This will make your application available at http://localhost:8080 (if you’re already using port 8080 on your machine, you’ll get a warning. Just pick a different port number, PHP doesn’t care what you bind it to).
能夠經過http://localhost:8080訪問你的slim應用(若是您的計算機上已經使用端口8080,您將獲得一個警告。只需選擇一個不一樣的端口號,PHP並不關心具體的端口號是什麼)。
To get this set up on a standard LAMP stack, we’ll need a couple of extra ingredients: some virtual host configuration, and one rewrite rule.
要在標準LAMP堆棧上設置此功能,咱們須要一些額外的組件:一些虛擬主機配置和一個重寫規則。
The vhost configuration should be fairly straightforward; we don’t need anything special here. Copy your existing default vhost configuration and set the ServerName to be how you want to refer to your project. For example you can set:
vhost配置應該至關簡單;咱們這裏不須要什麼特別的東西。複製現有的默認vhost配置,並將ServerName設置爲您但願引用項目的方式。例如,你能夠設置:
ServerName slimproject.test
or for nginx:
server_name slimproject.test;
複製代碼
Then you’ll also want to set the DocumentRoot to point to the public/ directory of your project, something like this (edit the existing line):
而後,您還須要將DocumentRoot設置爲指向項目的公共/目錄,以下所示(編輯現有行):
DocumentRoot /home/lorna/projects/slim/project/src/public/
or for nginx:
root /home/lorna/projects/slim/project/src/public/
複製代碼
Don’t forget to restart your server process now you’ve changed the configuration! I also have a .htaccess file in my src/public directory; this relies on Apache’s rewrite module being enabled and simply makes all web requests go to index.php so that Slim can then handle all the routing for us. Here’s my .htaccess file:
不要忘記從新啓動您的服務器進程,如今您已經更改了配置!
個人src/public目錄中也有一個.htaccess文件;這依賴於啓用Apache的重寫模塊,並簡單地將全部web請求轉到index.php,這樣Slim就能夠爲咱們處理全部路由。這是個人.htaccess文件:
RewriteEngine on
RewriteCond %{REQUEST_FILENAME} !-d
RewriteCond %{REQUEST_FILENAME} !-f
RewriteRule . index.php [L]
複製代碼
nginx does not use .htaccess files, so you will need to add the following to your server configuration in the location block:
nginx不使用.htaccess文件,因此您須要在location塊中向服務器配置添加如下內容:
if (!-e $request_filename){
rewrite ^(.*)$ /index.php break;
}
複製代碼
NOTE: If you want your entry point to be something other than index.php you will need your config to change as well. api.php is also commonly used as an entry point, so your set up should match accordingly. This example assumes you are using index.php.
注意:若是但願入口點不是index.php,還須要修改配置,api.php也一般用做入口點,所以您的設置應該相應地匹配。本例假設您正在使用index.php。
With this setup, just remember to use slimproject.test instead of http://localhost:8080 in the other examples in this tutorial. The same health warning as above applies: you’ll see an error page at slimproject.test but crucially it’s Slim’s error page. If you go to slimproject.test/hello/joebl… then something better should happen.
使用此設置,只需記住使用http://slimproject。在本教程的其餘示例中,測試而不是http://localhost:8080。上面的健康警告一樣適用:您將在http://slimproject中看到一個錯誤頁面。但關鍵是這是Slim的錯誤頁面。若是你訪問http://slimproject.test/hello/joebloggs而後應該會發生更好的事情。
Now we’ve set up the platform, we can start getting everything we need in place in the application itself.
如今咱們已經創建了平臺,咱們能夠開始在應用程序中得到所需的一切。
The initial example uses all the Slim defaults, but we can easily add configuration to our application when we create it. There are a few options but here I’ve just created an array of config options and then told Slim to take its settings from here when I create it. First the configuration itself:
如今咱們已經創建了平臺,咱們能夠開始在應用程序自己中得到所需的一切。
嚮應用程序添加配置設置
最初的示例使用了全部Slim缺省值,可是咱們能夠在建立應用程序時輕鬆地將配置添加到應用程序中。但這裏我只是建立了一個配置選項數組,而後告訴Slim在我建立它時從這裏獲取設置。
首先配置自己:
$config['displayErrorDetails'] = true;
$config['addContentLengthHeader'] = false;
$config['db']['host'] = 'localhost';
$config['db']['user'] = 'user';
$config['db']['pass'] = 'password';
$config['db']['dbname'] = 'exampleapp';
複製代碼
These string should be added into src/public/index.php before the $app = new \Slim\App line.
這些字符串應該在$app = new \Slim\ app行以前添加到src/public/index.php中。
The first line is the most important! Turn this on in development mode to get information about errors (without it, Slim will at least log errors so if you’re using the built in PHP webserver then you’ll see them in the console output which is helpful). The second line allows the web server to set the Content-Length header which makes Slim behave more predictably.
第一行是最重要的!在開發模式中打開此選項,以獲取有關錯誤的信息(若是沒有它,Slim至少會記錄錯誤,所以若是您正在使用內置的PHP webserver,那麼您將在控制檯輸出中看到這些錯誤,這頗有幫助)。第二行容許web服務器設置Content-Length報頭,這使得Slim的行爲更加可預測。
The other settings here are not specific keys/values, they’re just some data that I want to be able to access later.
Now to feed this into Slim, we need to change where we create the Slim/App object so that it now looks like this:
這裏的其餘設置不是特定的鍵/值,它們只是我但願之後可以訪問的一些數據。
如今,要把這個輸入Slim,咱們須要改變要建立的Slim/App對象,使它看起來像這樣:
$app = new \Slim\App(['settings' => $config]);
複製代碼
We’ll be able to access any settings we put into that $config array from our application later on.
稍後,咱們將可以從應用程序中訪問放入$config數組中的任何設置。
Composer can handle the autoloading of your own classes just as well as the vendored ones. For an in-depth guide, take a look at using Composer to manage autoloading rules.
Composer能夠像處理vendored類同樣處理您本身類的自動加載。要得到深刻的指導,請查看如何使用Composer管理自動加載規則。
My setup is pretty simple since I only have a few extra classes, they’re just in the global namespace, and the files are in the src/classes/ directory. So to autoload them, I add this autoload section to my composer.json file:
個人設置很是簡單,由於我只有幾個額外的類,它們只是在全局名稱空間中,而文件在src/classes/目錄中。所以,爲了自動加載它們,我將這個自動加載部分添加到composer.json文件:
{
"require": {
"slim/slim": "^3.1",
"slim/php-view": "^2.0",
"monolog/monolog": "^1.17",
"robmorgan/phinx": "^0.5.1"
},
"autoload": {
"psr-4": {
"": "classes/"
}
}
}
複製代碼
Most applications will have some dependencies, and Slim handles them nicely using a DIC (Dependency Injection Container) built on Pimple. This example will use both Monolog and a PDO connection to MySQL.
大多數應用程序都有一些依賴關係,Slim使用構建在Pimple上的DIC(依賴注入容器)很好地處理這些依賴關係。本例將使用monolog和MySQL的PDO鏈接。
The idea of the dependency injection container is that you configure the container to be able to load the dependencies that your application needs, when it needs them. Once the DIC has created/assembled the dependencies, it stores them and can supply them again later if needed.
依賴項注入容器的思想是,將容器配置爲可以在應用程序須要依賴項時加載它們。一旦DIC建立/組裝了依賴項,它就會存儲依賴項,並在之後須要時再次提供依賴項。
To get the container, we can add the following after the line where we create $app and before we start to register the routes in our application:
要得到容器,咱們能夠在建立$app的行後面,註冊路由的前面添加如下內容:
$container = $app->getContainer();
複製代碼
Now we have the Slim\Container object, we can add our services to it.
如今咱們有了Slim\Container對象,能夠將服務添加到其中。
If you’re not already familiar with Monolog, it’s an excellent logging framework for PHP applications, which is why I’m going to use it here. First of all, get the Monolog library installed via Composer:
若是您還不熟悉Monolog,它是一個很是好的PHP應用程序日誌框架,這就是爲何我要在這裏使用它。首先,經過Composer安裝monolog庫:
php composer.phar require monolog/monolog
複製代碼
The dependency is named logger and the code to add it looks like this:
依賴項命名爲logger,添加它的代碼以下:
$container['logger'] = function($c) {
$logger = new \Monolog\Logger('my_logger');
$file_handler = new \Monolog\Handler\StreamHandler('../logs/app.log');
$logger->pushHandler($file_handler);
return $logger;
};
複製代碼
We’re adding an element to the container, which is itself an anonymous function (the $c that is passed in is the container itself so you can access other dependencies if you need to). This will be called when we try to access this dependency for the first time; the code here does the setup of the dependency. Next time we try to access the same dependency, the same object that was created the first time will be used the next time.
咱們正在向容器添加一個元素,它自己是一個匿名函數(傳入的$c是容器自己,所以若是須要,您能夠訪問其餘依賴項)。當咱們第一次嘗試訪問這個依賴項時,它將被調用;這裏的代碼負責設置依賴項。下次咱們嘗試訪問相同的依賴項時,將使用第一次建立的相同對象。
My Monolog config here is fairly light; just setting up the application to log all errors to a file called logs/app.log (remember this path is from the point of view of where the script is running, i.e. index.php).
這裏的Monolog配置至關簡單;只需設置應用程序將全部錯誤記錄到一個名爲logs/app.log的文件中(請記住,該路徑是從腳本運行的角度來看的,即index.php)。
With the logger in place, I can use it from inside my route code with a line like this:
有了logger,我能夠在個人路由代碼內這樣使用它:
$this->logger->addInfo('Something interesting happened');
複製代碼
Having good application logging is a really important foundation for any application so I’d always recommend putting something like this in place. This allows you to add as much or as little debugging as you want, and by using the appropriate log levels with each message, you can have as much or as little detail as is appropriate for what you’re doing in any one moment.
對於任何應用程序來講,良好的應用程序日誌記錄都是很是重要的基礎,因此我老是建議在適當的地方使用相似的日誌記錄。這容許您根據須要添加儘量多或儘量少的調試,而且經過對每一個消息使用適當的日誌級別,您能夠在任什麼時候刻得到儘量多或儘量少的細節。
There are many database libraries available for PHP, but this example uses PDO - this is available in PHP as standard so it’s probably useful in every project, or you can use your own libraries by adapting the examples below.
有許多數據庫庫可供PHP使用,可是本例使用PDO—這在PHP中是標準的,因此它可能在每一個項目中都頗有用,或者您能夠經過調整下面的示例來使用本身的庫。
Exactly as we did for adding Monolog to the DIC(dependency injection container), we’ll add an anonymous function that sets up the dependency, in this case called db:
正如咱們在向DIC(依賴注入容器)添加Monolog時所作的那樣,咱們將添加一個匿名函數來設置依賴關係,在本例中稱爲db:
$container['db'] = function ($c) {
$db = $c['settings']['db'];
$pdo = new PDO('mysql:host=' . $db['host'] . ';dbname=' . $db['dbname'],
$db['user'], $db['pass']);
$pdo->setAttribute(PDO::ATTR_ERRMODE, PDO::ERRMODE_EXCEPTION);
$pdo->setAttribute(PDO::ATTR_DEFAULT_FETCH_MODE, PDO::FETCH_ASSOC);
return $pdo;
};
複製代碼
Remember the config that we added into our app earlier? Well, this is where we use it - the container knows how to access our settings, and so we can grab our configuration very easily from here. With the config, we create the PDO object (remember this will throw a PDOException if it fails and you might like to handle that here) so that we can connect to the database. I’ve included two setAttribute() calls that really aren’t necessary but I find these two settings make PDO itself much more usable as a library so I left the settings in this example so you can use them too! Finally, we return our connection object.
還記得咱們以前添加到應用程序中的配置嗎?這就是咱們使用它的地方——容器知道如何訪問咱們的設置,所以咱們能夠很容易地從這裏獲取配置。經過配置,咱們建立了PDO對象(請記住,若是它失敗,將拋出一個PDOException,您可能但願在這裏處理它),以便咱們能夠鏈接到數據庫。我已經包含了兩個setAttribute()調用,這其實是沒必要要的,但我發現這兩個設置使PDO自己做爲一個庫更有用,因此我在本例中保留了這些設置,以便您也可使用它們!最後,返回connection對象。
Again, we can access our dependencies with just $this-> and then the name of the dependency we want which in this case is $this->db, so there is code in my application that looks something like:
一樣,咱們能夠用$this->方式訪問咱們的依賴,後面跟上咱們想要的依賴名稱,在本例中是$this->db,因此個人應用程序中的代碼看起來像:
$mapper = new TicketMapper($this->db);
複製代碼
This will fetch the db dependency from the DIC, creating it if necessary, and in this example just allows me to pass the PDO object straight into my mapper class.
這將從DIC獲取db依賴項,在必要時建立它,在本例中只容許我將PDO對象直接傳遞到映射器類中。
「Routes」 are the URL patterns that we’ll describe and attach functionality to. Slim doesn’t use any automatic mapping or URL formulae so you can make any route pattern you like map onto any function you like, it’s very flexible. Routes can be linked to a particular HTTP verb (such as GET or POST), or more than one verb.
「路由」是咱們將描述並附加功能的URL模式。Slim沒有使用任何自動映射或URL公式,因此您能夠將任何您喜歡的路由模式映射到任何您喜歡的函數上,這是很是靈活的。路由能夠連接到特定的HTTP動做(如GET或POST),也能夠連接到多個動做。
As a first example, here’s the code for making a GET request to /tickets which lists the tickets in my bug tracker example application. It just spits out the variables since we haven’t added any views to our application yet:
做爲第一個示例,下面是向/tickets發出GET請求的代碼,它列出了個人bug跟蹤器示例應用程序中的罰單。它只是吐出變量,由於咱們尚未添加任何視圖到咱們的應用程序:
$app->get('/tickets', function (Request $request, Response $response) {
$this->logger->addInfo("Ticket list");
$mapper = new TicketMapper($this->db);
$tickets = $mapper->getTickets();
$response->getBody()->write(var_export($tickets, true));
return $response;
});
複製代碼
The use of $app->get() here means that this route is only available for GET requests; there’s an equivalent $app->post() call that also takes the route pattern and a callback for POST requests. There are also methods for other verbs - and also the map() function for situations where more than one verb should use the same code for a particular route.
這裏使用$app->get()意味着此路由僅對get請求可用;還有一個等效的$app->post()調用,它也接受路由模式和post請求的回調。還有用於其餘謂詞的方法,以及map()函數,用於多個謂詞對特定路由使用相同代碼的狀況。
Slim routes match in the order they are declared, so if you have a route which could overlap another route, you need to put the most specific one first. Slim will throw an exception if there’s a problem, for example in this application I have both /ticket/new and /ticket/{id} and they need to be declared in that order otherwise the routing will think that 「new」 is an ID!
Slim路由按照聲明的順序匹配,所以,若是您有一個可能與另外一個路由重疊的路由,那麼您須要首先放置最具體的一個。若是有問題,Slim會拋出異常,例如在這個應用程序中,我同時擁有/ticket/new和/ticket/{id},它們須要按這個順序聲明,不然路由會認爲「new」是一個id !
In this example application, all the routes are in index.php but in practice this can make for a rather long and unwieldy file! It’s fine to refactor your application to put routes into a different file or files, or just register a set of routes with callbacks that are actually declared elsewhere.
在這個示例應用程序中,全部的路由都在index.php中,但實際上這可能致使文件很長且很笨重!能夠重構應用程序,將路由放入一個或多個不一樣的文件中,或者只註冊一組路由,而將其中的回調部分放到其餘地方。
All route callbacks accept three parameters (the third one is optional):
全部路由回調都接受三個參數(第三個是可選的):
This emphasis on Request and Response illustrates Slim 3 being based on the PSR-7 standard for HTTP Messaging. Using the Request and Response object also makes the application more testable as we don’t need to make actual requests and responses, we can just set up the objects as desired.
這種對請求和響應的強調說明了Slim 3基於HTTP消息傳遞的PSR-7標準。使用請求和響應對象還可使應用程序更具可測試性,由於咱們不須要進行實際的請求和響應,咱們能夠根據須要設置對象。
Sometimes, our URLs have variables in them that we want to use in our application. In my bug tracking example, I want to have URLs like /ticket/42 to refer to the ticket - and Slim has an easy way of parsing out the 「42」 bit and making it available for easy use in the code. Here’s the route that does exactly that:
有時,url中有一些變量,咱們但願在應用程序中使用這些變量。在個人bug跟蹤示例中,我但願有像/ticket/42這樣的url來引用票據——Slim有一種簡單的方法來解析「42」位並使其在代碼中易於使用。下面就是具體的方法:
$app->get('/ticket/{id}', function (Request $request, Response $response, $args) {
$ticket_id = (int)$args['id'];
$mapper = new TicketMapper($this->db);
$ticket = $mapper->getTicketById($ticket_id);
$response->getBody()->write(var_export($ticket, true));
return $response;
});
複製代碼
Look at where the route itself is defined: we write it as /ticket/{id}. When we do this, the route will take the portion of the URL from where the {id} is declared, and it becomes available as $args['id'] inside the callback.
查看路由自己的定義位置:咱們將它寫爲/ticket/{id}。當咱們這樣作時,該路由將從聲明{id}的URL中提取部分,並在回調函數中以$args['id']的形式被使用。
Since GET and POST send data in such different ways, then the way that we get that data from the Request object differs hugely in Slim.
因爲GET和POST以如此不一樣的方式發送數據,因此咱們從請求對象獲取數據的方式在Slim中有很大的不一樣。
It is possible to get all the query parameters from a request by doing $request->getQueryParams() which will return an associative array. So for the URL /tickets?sort=date&order=desc we’d get an associative array like:
經過執行$request->getQueryParams()能夠從請求中得到全部查詢參數,該方法將返回一個關聯數組。URL /tickes?sort=date&order=desc咱們會獲得一個關聯數組,以下所示:
['sort' => 'date', 'order' => 'desc']
複製代碼
These can then be used (after validating of course) inside your callback.
而後能夠在回調中使用它們(固然是在驗證以後)。
When working with incoming data, we can find this in the body. We’ve already seen how we can parse data from the URL and how to obtain the GET variables by doing $request->getQueryParams() but what about POST data? The POST request data can be found in the body of the request, and Slim has some good built in helpers to make it easier to get the information in a useful format.
當處理傳入數據時,咱們能夠在主體中找到這些數據。咱們已經瞭解瞭如何解析URL中的數據,以及如何經過執行$request->getQueryParams()得到GET變量,可是POST數據呢?POST請求數據能夠在請求體中找到,Slim內置一些很好的幫助程序,能夠更容易地得到格式化後的有用信息。
For data that comes from a web form, Slim will turn that into an array. My tickets example application has a form for creating new tickets that just sends two fields: 「title」 and 「description」. Here is the first part of the route that receives that data, note that for a POST route use app->get():
對於來自web表單的數據,Slim將其轉換爲數組。個人tickets示例應用程序有一個用於建立新罰單的表單,它只發送兩個字段:「title」和「description」。這裏是接收數據的路由的第一部分,注意對於POST路由使用app->get():
$app->post('/ticket/new', function (Request $request, Response $response) {
$data = $request->getParsedBody();
$ticket_data = [];
$ticket_data['title'] = filter_var($data['title'], FILTER_SANITIZE_STRING);
$ticket_data['description'] = filter_var($data['description'], FILTER_SANITIZE_STRING);
// ...
複製代碼
The call to $request->getParsedBody() asks Slim to look at the request and the Content-Type headers of that request, then do something smart and useful with the body. In this example it’s just a form post and so the resulting $data array looks very similar to what we’d expect from $_POST - and we can go ahead and use the filter extension to check the value is acceptable before we use it. A huge advantage of using the built in Slim methods is that we can test things by injecting different request objects - if we were to use $_POST directly, we aren’t able to do that.
對$request->getParsedBody()的調用要求Slim查看請求和該請求的內容類型頭,而後對該請求的正文作一些智能的操做。在本例中,它只是一個表單post,所以生成的$data數組與咱們指望的$_POST很是類似——在使用它以前,咱們能夠繼續使用filter擴展來檢查值是否能夠接受。使用內置Slim方法的一個巨大優點是,咱們能夠經過注入不一樣的請求對象來測試—若是直接使用$_POST,咱們就不能這樣作。
What’s really neat here is that if you’re building an API or writing AJAX endpoints, for example, it’s super easy to work with data formats that arrive by POST but which aren’t a web form. As long as the Content-Type header is set correctly, Slim will parse a JSON payload into an array and you can access it exactly the same way: by using $request->getParsedBody().
這裏真正簡潔的地方是,若是您正在構建API或編寫AJAX站點,那麼處理經過POST到達但不是web表單的數據格式就很是容易。只要正確設置了Content-Type頭部,Slim就會將JSON有效負載解析爲一個數組,您可使用徹底相同的方法訪問它:使用$request->getParsedBody()。
Slim doesn’t have an opinion on the views that you should use, although there are some options that are ready to plug in. Your best choices are either Twig or plain old PHP. Both options have pros and cons: if you’re already familiar with Twig then it offers lots of excellent features and functionality such as layouts - but if you’re not already using Twig, it can be a large learning curve overhead to add to a microframework project. If you’re looking for something dirt simple then the PHP views might be for you! I picked PHP for this example project, but if you’re familiar with Twig then feel free to use that; the basics are mostly the same.
Slim對您應該使用的視圖沒有任何意見,不過有一些選項能夠插入。您最好的選擇是Twig或普通的老式PHP。這兩種選擇都有優缺點:若是您已經熟悉Twig,那麼它提供了許多優秀的特性和功能,好比佈局——可是若是您尚未使用Twig,那麼將其添加到微框架項目中可能須要花費大量的學習時間。若是您正在尋找一些很是簡單的東西,那麼PHP視圖可能適合您!我選擇PHP做爲這個示例項目,可是若是您熟悉Twig,那麼能夠隨意使用它;基本是同樣的。
Since we’ll be using the PHP views, we’ll need to add this dependency to our project via Composer. The command looks like this (similar to the ones you’ve already seen):
因爲咱們將使用PHP視圖,所以須要經過Composer將此依賴項添加到項目中。命令看起來是這樣的(相似於您已經看到的命令):
php composer.phar require slim/php-view
複製代碼
In order to be able to render the view, we’ll first need to create a view and make it available to our application; we do that by adding it to the DIC. The code we need goes with the other DIC additions near the top of src/public/index.php and it looks like this:
爲了可以呈現視圖,咱們首先須要建立一個視圖並使它對咱們的應用程序可用;咱們把它加到DIC中。咱們須要的代碼與src/public/index.php頂部的其餘DIC附加代碼一塊兒使用,它看起來是這樣的:
$container['view'] = new \Slim\Views\PhpRenderer('../templates/');
複製代碼
Now we have a view element in the DIC, and by default it will look for its templates in the src/templates/ directory. We can use it to render templates in our actions - here’s the ticket list route again, this time including the call to pass data into the template and render it:
如今DIC中有一個view元素,默認狀況下,它將在src/templates/目錄中查找它的模板。在咱們的控制器中咱們使用它來渲染模板,這一次包括調用傳遞數據到模板和渲染它:
$app->get('/tickets', function (Request $request, Response $response) {
$this->logger->addInfo('Ticket list');
$mapper = new TicketMapper($this->db);
$tickets = $mapper->getTickets();
$response = $this->view->render($response, 'tickets.phtml', ['tickets' => $tickets]);
return $response;
});
複製代碼
The only new part here is the penultimate line where we set the $response variable. Now that the view is in the DIC, we can refer to it as $this->view. Calling render() needs us to supply three arguments: the $response to use, the template file (inside the default templates directory), and any data we want to pass in. Response objects are immutable which means that the call to render() won’t update the response object; instead it will return us a new object which is why it needs to be captured like this. This is always true when you operate on the response object.
這裏唯一的新部分是設置$response變量的倒數第二行。既然視圖在DIC中,咱們能夠將其稱爲$this->view。調用render()須要提供三個參數:要使用的$response、模板文件(在默認模板目錄中)和任何咱們但願傳入的數據。響應對象是不可變的,這意味着render()調用不會更新響應對象;相反,它將返回一個新對象,這就是爲何須要像這樣捕獲它。當您對響應對象進行操做時,就須要這樣作才行。
When passing the data to templates, you can add as many elements to the array as you want to make available in the template. The keys of the array are the variables that the data will exist in once we get to the template itself.
當將數據傳遞給模板時,您能夠向數組中添加儘量多的元素,使其在模板中可用。數組的鍵將以變量的形式在模板中存在。
As an example, here’s a snippet from the template that displays the ticket list (i.e. the code from src/templates/tickets.phtml - which uses Pure.css to help cover my lack of frontend skills):
例如,下面是顯示門票列表的模板代碼片斷(即src/templates/tickets.phtml中的代碼-它使用Pure.css來幫助彌補我缺少的前端技能):
<h1>All Tickets</h1>
<p><a href="/ticket/new">Add new ticket</a></p>
<table class="pure-table">
<tr>
<th>Title</th>
<th>Component</th>
<th>Description</th>
<th>Actions</th>
</tr>
<?php foreach ($tickets as $ticket): ?>
<tr>
<td><?=$ticket->getTitle() ?></td>
<td><?=$ticket->getComponent() ?></td>
<td><?=$ticket->getShortDescription() ?> ...</td>
<td>
<a href="<?=$router->pathFor('ticket-detail', ['id' => $ticket->getId()])?>">view</a>
</td>
</tr>
<?php endforeach; ?>
</table>
複製代碼
In this case, $tickets is actually a TicketEntity class with getters and setters, but if you passed in an array, you’d be able to access it using array rather than object notation here.
Did you notice something fun going on with $router->pathFor() right at the end of the example? Let’s talk about named routes next :)
在本例中,$tickets其實是一個帶有getter和setter的TicketEntity類,但若是傳入一個數組,則可使用數組而不是這裏的對象符號訪問它。
您是否注意到$router->pathFor()在示例的末尾發生了一些有趣的事情?下面讓咱們討論命名路由:)
When we create a route, we can give it a name by calling ->setName() on the route object. In this case, I am adding the name to the route that lets me view an individual ticket so that I can quickly create the right URL for a ticket by just giving the name of the route, so my code now looks something like this (just the changed bits shown here):
當咱們建立一個路由時,咱們能夠經過調用route對象上的->setName()爲它命名。在這種狀況下,咱們經過給查看機票詳情的路由起一個名字,所以僅憑這個路由名字就能夠快速建立正確的URL,因此如今個人代碼是這樣的(只是更改的部分所示):
$app->get('/ticket/{id}', function (Request $request, Response \$response, $args) {
// ...
})->setName('ticket-detail');
複製代碼
To use this in my template, I need to make the router available in the template that’s going to want to create this URL, so I’ve amended the tickets route to pass a router through to the template by changing the render line to look like this:
要在個人模板中使用這個,咱們須要用router變量來生成次URL,因此就像下面這樣,我經過改變render這行代碼,將路由中的router傳入模板來實現:
$response = $this->view->render($response, 'tickets.phtml', ['tickets' => $tickets, 'router' => $this->router]);
複製代碼
With the /tickets/{id} route having a friendly name, and the router now available in our template, this is what makes the pathFor() call in our template work. By supplying the id, this gets used as a named placeholder in the URL pattern, and the correct URL for linking to that route with those values is created. This feature is brilliant for readable template URLs and is even better if you ever need to change a URL format for any reason - no need to grep templates to see where it’s used. This approach is definitely recommended, especially for links you’ll use a lot.
因爲/tickets/{id}路由有一個友好的名稱,而且router對象如今能夠在模板中使用,這就是使模板中的pathFor()調用起做用的緣由。經過提供id,能夠在URL模式中將其用做命名佔位符,而後經過這些值創建連接到該路由的正確URL。這個特性對於可讀的模板URL來講是很是棒的,若是您曾經由於一些緣由須要更改URL格式—不須要使用grep模板來查看它的使用位置,那麼這個特性甚至更好。這種方法絕對值得推薦,特別是對於您將常用的連接。
This article gave a walkthrough of how to get set up with a simple application of your own, which I hope will let you get quickly started, see some working examples, and build something awesome.
本文簡要介紹瞭如何使用您本身的簡單應用程序進行設置,我但願這將使您快速入門,看到一些工做示例,並構建一些很棒的東西。
From here, I’d recommend you take a look at the other parts of the project documentation for anything you need that wasn’t already covered or that you want to see an alternative example of. A great next step would be to take a look at the Middleware section - this technique is how we layer up our application and add functionality such as authentication which can be applied to multiple routes.
從這裏開始,我建議您查看項目文檔的其餘部分,瞭解您須要的任何內容,這些內容尚未涵蓋,或者您但願看到另外一個示例。下一個重要的步驟是查看中間件部分——該技術是咱們如何分層應用程序並添加諸如身份驗證之類的功能,這些功能能夠應用於多個路由。