Slim

Slim

2020/04/18 

2020/04/27 (補充內容)

介紹

Slim 是一個 PHP 微型框架,可以協助快速建立強勁的 Web應用和 API。即便 Slim 所提供的功能沒有 Laravel 完整,但對於撰寫一個 API 也是十分足夠的了。

安裝環境

*下載 Slim 前請先安裝 Composer ;啟動伺服器前要先安裝 PHP

slim-skeleton

 Slim 官網有提供 slim-skeleton,這是已經做好初始設置的 Slim 專案,讓我們可以更快速地建構一個後端服務。

在你要放置專案資料夾的路徑下,打開終端機輸入以下指令:

$ composer create-project slim/slim-skeleton [my-app-name]

[ my-app-name ] 的部分輸入專案資料夾的名稱。

例如:

$ composer create-project slim/slim-skeleton myApp

執行後,會產生一個新資料夾,可以進入該資料夾。

終端機前往創建的專案資料夾下;

$ cd [my-app-name]

例如:

$ cd myApp

執行php,-S 指定server的位址與port,-t 指定開啟的目錄

輸入 php 指令開啟伺服器,這邊使用 port:8080 為載入點。

$ php -S localhost:8080 -t public public/index.php

也可以利用composer來啟動 (事實上跟上一個動作是一樣的)

$ composer start

在瀏覽器打開localhost:8080,會看到

Hello world!

到創建的專案資料夾底下,可以看到一些檔案及資料夾,這些都是透過slim-skeleton產生的,有:

詳參: Slim 4 Skelenton

但是 slim-skeleton 是一個完整的後端專案,結構與內容對新手來說過於複雜,修改內容也相較比較困難。讓我們先從基礎的 Slim 開始練習:

Installation

前面的做法會幫我們新增一個資料夾,但是,以下的做法不一樣,要先自己新增一個專案資料夾。

首先在專案資料夾安裝 slim 與 psr7,打開終端機輸入以下指令:

$ composer require slim/slim:"4.*" slim/psr7

這個指令要求composer安裝slim以及psr7。

PSR,全名 PHP Standards Recommendations,是一個由非官方委員會 PHP-FIG 所提出的一系列標準。PSR-7主要是定義HTTP 訊息介面。(詳參: Day 03:PSR-12 概述PSR-7 帶來的變革)

安裝完成後,會發現在資料夾下多了兩個檔案: composer.json及composer.lock,這兩個檔案是composer的設定檔。並且多了一個vendor的檔案夾,裡面就是剛剛我們利用composer安裝slim及psr的檔案。

接下來,在專案資料夾新增名為 public 的資料夾,並新增 index.php 的檔案。

index.phpslim 官網提供的程式碼貼上:

<?php


use Psr\Http\Message\ResponseInterface as Response;

use Psr\Http\Message\ServerRequestInterface as Request;

use Slim\Factory\AppFactory;


require __DIR__ . '/../vendor/autoload.php';


$app = AppFactory::create();


$app->get('/', function (Request $request, Response $response, $args) {

    $response->getBody()->write("Hello world!");

    return $response;

});


$app->run();

後面會針對以上程式碼作一些簡單的講解。

在php裡,use就好像是java的 import一樣,這些都是php的檔案,放在對應的路徑中。

接下來開啟伺服器:

$ php -S localhost:8080 -t public public/index.php

如果覺得這個太長,很難記,可以修改一下composer.json,加上scripts

{

    "require": {

        "slim/slim": "4.*",

        "slim/psr7": "^1.0"

    },

    "scripts": {

        "start": "php -S localhost:8080 -t public"

    }

}

這樣的話,就可以利用composer啟動伺服器了

$ composer start

這時候在網址列打上 http://localhost:8080/,會看到預設的首頁:




Hello World!

資料庫

接下來繼續介紹如何抓取資料庫資料,並透過 API路徑傳值。

這邊繼續使用上面手動建置的專案,首先在專案目錄新增一個 config 資料夾,並新增一個 database.php


config / database.php

<?php


return [

'host' => '127.0.0.1',

'port' => '8889',

'charset' => 'utf8',

'database' => 'test_wallet',

'username' => 'root',

'password' => 'root',

];


database.php 直接回傳連線資料庫的初始設置:


接著在專案資料夾下再新增一個 lib 資料夾,並新增 DB.phpbootstrap.php 兩個檔案。

可以參考先前課堂上所教的連線方式,直接接取PDO物件引入之後的檔案:


lib / DB.php

<?php


$config = require __DIR__ . '/../config/database.php';


$host = $config['host'] ?? '127.0.0.1';

$port = $config['port'] ?? '8889';

$charset = $config['charset'] ?? 'utf8';

$database = $config['database'] ?? 'test_wallet';

$username = $config['username'] ?? 'root';

$password = $config['password'] ?? 'root';


try 

{

  $conn = new PDO(

    "mysql:host={$host};port={$port};charset={$charset};dbname={$database}",

    $username,

    $password

  );

  $conn->setAttribute(PDO::ATTR_ERRMODE, PDO::ERRMODE_EXCEPTION);

}

catch(PDOException $e)

{

  echo "Connection failed: " . $e->getMessage();

}

lib / bootstrap.php

<?php


require __DIR__ . '/DB.php';


接著在 index.php 將資料庫引入:

public / index.php

<?php


use Psr\Http\Message\ResponseInterface as Response;

use Psr\Http\Message\ServerRequestInterface as Request;

use Slim\Factory\AppFactory;


require __DIR__ . '/../vendor/autoload.php';

require __DIR__ . '/../lib/bootstrap.php';


$app = AppFactory::create();


$app->get('/', function (Request $request, Response $response, $args) {


$response->getBody()->write("Hello world!");


return $response;

});

這樣基本的資料庫物件就設置好了。


API 路由

資料庫建置好了,接下來就要來介紹如何將資料庫的資料接出,並設置路徑輸出,讓前端可以透過這個 API 位址獲得資料。

打開 index.php,首先先介紹一下路由設置的內容:

$app->get('/', function (Request $request, Response $response, $args) {


  $response->getBody()->write("Hello World");


  return $response;

});


新增一個服務位址輸出資料庫,這邊以資料庫中的 users 資料表為例:

$app->get('/users', function (Request $request, Response $response, $args) {


  global $conn;//讀取全域變數


  $sql="SELECT * FROM `USERS`";

  $stmt = $conn->prepare($sql);

  $stmt->execute();

  $users = $stmt->fetchAll(PDO::FETCH_ASSOC);//二維陣列讀取


  $response->getBody()->write(json_encode($users));//json_encode()將陣列格式轉換成Json型態


  return $response;


});

讀取資料表中所有資料

$app->get('/users/{id}', function (Request $request, Response $response, $args) {


  global $conn;


  $id = $args['id'];


  $sql="SELECT * FROM `USERS` WHERE id = :id";

  $stmt = $conn->prepare($sql);

  $stmt->execute(['id'=> $id ?? '1']);

  $users = $stmt->fetch(PDO::FETCH_ASSOC);//一維陣列讀取


  $response->getBody()->write(json_encode($users));


  return $response;

});

讀取資料表中符合條件(  id  )的所有欄位資料


第二個範例較特別的是,路由可以讀取 url 中的值作為變數。這邊路徑 /users 後面的位址設置為變數 id,透過 $args['id'] 讀取,所以可以依照路徑不同抓取不同 id 的資料,而不用為每個 id 個別設置一個位址。

這時候在網址列打上 http://localhost:8080/users,會看到資料表輸出的資料:

http://localhost:8080/users/1 讀取資料表指定 id 資料:

如果,資料表裡的資料有中文字,會被encode。

[{"id":"1","role":"M","account":"405401372","name":"\u4f0d\u5ead\u5100","seat":"22","credit":"500","wish_list":"[]","purchase_list":"[]","created_at":"2019-10-27","updated_at":"2019-11-22 15:09:31","deleted_at":null},{"id":"2","role":"M","account":"405401607","name":"\u9ad8\u5b50\u8ed2","seat":"66","credit":"0","wish_list":null,"purchase_list":"[]","created_at":"2019-10-27","updated_at":"2019-11-22 13:30:30","deleted_at":null}]

所以,就要加上JSON_UNESCAPED_UNICODE,告訴json_encode,不要把unicode (utf-8)的文字encode。

$response->getBody()->write(json_encode($users, JSON_UNESCAPED_UNICODE));

這時候,中文字就不會被encode了。

[{"id":"1","role":"M","account":"405401372","name":"伍庭儀","seat":"22","credit":"500","wish_list":"[]","purchase_list":"[]","created_at":"2019-10-27","updated_at":"2019-11-22 15:09:31","deleted_at":null},{"id":"2","role":"M","account":"405401607","name":"高子軒","seat":"66","credit":"0","wish_list":null,"purchase_list":"[]","created_at":"2019-10-27","updated_at":"2019-11-22 13:30:30","deleted_at":null}]

完整的index.php:

<?php


use Psr\Http\Message\ResponseInterface as Response;

use Psr\Http\Message\ServerRequestInterface as Request;

use Slim\Factory\AppFactory;


require __DIR__ . '/../vendor/autoload.php';

require __DIR__ . '/../lib/bootstrap.php';


$app = AppFactory::create();


$app->get('/', function (Request $request, Response $response, $args) {

    $response->getBody()->write("Hello world, Ben!");

    return $response;

});


$app->get('/users', function (Request $request, Response $response, $args) {


    global $conn;//讀取全域變數

  

    $sql="SELECT * FROM `USERS`";

    $stmt = $conn->prepare($sql);

    $stmt->execute();

    $users = $stmt->fetchAll(PDO::FETCH_ASSOC);//二維陣列讀取

  

    $response->getBody()->write(json_encode($users, JSON_UNESCAPED_UNICODE));//json_encode()將陣列格式轉換成Json型態

  

    return $response;

  

  });


$app->get('/users/{id}', function (Request $request, Response $response, $args) {


    global $conn;

  

    $id = $args['id'];

  

    $sql="SELECT * FROM `USERS` WHERE id = :id";

    $stmt = $conn->prepare($sql);

    $stmt->execute(['id'=> $id ?? '1']);

    $users = $stmt->fetch(PDO::FETCH_ASSOC);//一維陣列讀取

  

    $response->getBody()->write(json_encode($users, JSON_UNESCAPED_UNICODE));

  

    return $response;

  });


$app->run();