iT邦幫忙

第 12 屆 iThome 鐵人賽

DAY 1
0
Modern Web

Laravel 8: For Beginners系列 第 8

短網址服務(Part1)

前言

短網址服務是個簡單的小型服務,它可以考驗一些基本的資料庫操作(新增及查詢)。

附註

其實短網址服務可以是個水很深的專案,從短碼的生成方式、Redirector Server 的設計、流量統計等等都是可以深入探討的主題。

我們在這個篇章中不會探討這麼深入的主題,僅以純 Laravel 的短網址服務作為範例。

Spec

  • 輸入:Valid URL
  • 輸出:Shorted URL
  • 其它
    • 使用 SQLite

前置作業

安裝 Laravel

$ laravel new url-shorter

設定 Laravel

SQLite 連線與測試

要求使用 SQLite,所以先設定好 SQLite 的連線。

<?php

// config/database.php

return [
	'default' => env('DB_CONNECTION', 'sqlite'); // 這裡改成 SQLite

	'connections' => [
		// ...
		'sqlite' => [
			'driver' => 'sqlite',
			'url' => env('DATABASE_URL'),
			'database' => env('DB_DATABASE', database_path('database.sqlite')),
			'prefix' => '',
			'foreign_key_constraints' => env('DB_FOREIGN_KEYS', true),
		],
		// ...
	],
	// ...
];

我們可以看到在 connections.sqlite.database 中的值是 env('DB_DATABASE', database_path('database.sqlite'))

也就是說,在完全不設定的前提下,Laravel 會使用 database/database.sqlite 這個檔案作為 SQLite 儲存的位置。

首先,要先建立 SQLite 的儲存檔

$ touch database/database.sqlite

記得移除 .env 中的 DB_CONNECTION, DB_HOST, DB_PORT, DB_DATABASE, DB_USERNAME, DB_PASSWORD 值,如此才會套用 config/database.php 中的預設值。

我們可以嘗試執行 migrations 測試是否能夠正常連線

$ php artisan migrate # 執行 Migrate
Migration table created successfully.
Migrating: 2014_10_12_000000_create_users_table
Migrated:  2014_10_12_000000_create_users_table (3.72ms)
Migrating: 2014_10_12_100000_create_password_resets_table
Migrated:  2014_10_12_100000_create_password_resets_table (2.78ms)
Migrating: 2019_08_19_000000_create_failed_jobs_table
Migrated:  2019_08_19_000000_create_failed_jobs_table (2.89ms)
$ php artisan migrate:reset # 重置 Migrate
Rolling back: 2019_08_19_000000_create_failed_jobs_table
Rolled back:  2019_08_19_000000_create_failed_jobs_table (2.84ms)
Rolling back: 2014_10_12_100000_create_password_resets_table
Rolled back:  2014_10_12_100000_create_password_resets_table (1.22ms)
Rolling back: 2014_10_12_000000_create_users_table
Rolled back:  2014_10_12_000000_create_users_table (1.26ms)

移除不需要的 Migrations

因為 Laravel 有預設的 Migrations,會自動幫忙先建立 users, password_resets 及 failed_jobs,這在目前的我們是多餘的。

$ rm database/migrations/*.php

原型開發

讓 URL 可儲存在 SQLite 中

利用 Laravel Make Model 的功能,我們可以建立 URL Model 及其對應的 migrations。

$ php artisan make:model -m Url

其中的 -m 參數是用於順便建立 urls Table 的 Migration。

Schema 設計

<?php

// database/migrations/xxxx_xx_xx_xxxxxx_create_urls_table.php

// ...

class CreateUrlsTable extends Migration
{
	public function up()
	{
		Schema::create('urls', function (Blueprint $table) {
			$table->id();
			$table->string('url');
			$table->timestamps();
		});
	}

	public function down()
	{
		Schema::dropIfExists('urls');
	}
}
  • $table->id() 用於 Primary Key 的儲存,Laravel 預設是 Big Integer + Auto Increment
  • $table->string('url') 建立一個名為 url 的 column,用於儲存網址
  • $table->timestamps() 建立 created_atupdated_at 兩個 columns,Eloquent ORM 會自動維護這兩個 Columns

建立完成之後,不要忘記 php artisan migrate

Url Model 設計

<?php

// app/Models/Url.php

namespace App\Models;

use Illuminate\Database\Eloquent\Model;

class Url extends Model
{
	protected $fillable = ['url'];
}
  • $fillable 是用於 Url::create()$url->update() 時使用
    • 沒有在 $fillable 允許範圍內的 column 並不會被 create 及 update 修改

測試 Url Model 可以正常運作

利用 Artisan Tinker 的功能,我們可以輕鬆地與 Laravel 交互。

$ php artisan tinker
Psy Shell v0.10.4 (PHP 7.4.9 — cli) by Justin Hileman
>>>

以下示範一些 tinker shell 的使用方式

(tinker) > Url::create(['url' => 'www.google.com.tw']);
=> App\Url {#3985
     url: "https://www.google.com.tw",
     updated_at: "2020-01-01 00:00:00",
     created_at: "2020-01-01 00:00:00",
     id: 1,
   }
	}
(tinker) > Url::find(1)
=> App\Url {#3424
     id: "1",
     url: "https://www.google.com.tw",
     created_at: "2020-01-01 00:00:00",
     updated_at: "2020-01-01 00:00:00",
   }
(tinker) > Url::find(1)->update(['url' => 'https://www.yahoo.com.tw'])
=> true
(tinker) > Url::find(1)
=> App\Url {#3424
     id: "1",
     url: "https://www.yahoo.com.tw",
     created_at: "2020-01-01 00:00:00",
     updated_at: "2020-01-01 00:00:00",
   }

設計 API:縮網址

  • HTTP POST,參數僅有 url
  • 以字串型式回傳 Url Model 的 ID

Controller

$ php artisan make:controller ShorterController
<?php

// app/Http/Controllers/ShorterController.php

// ...

class ShorterController extends Controller
{
	public function __invoke(Request $request)
	{
		$shortedUrl = Url::create(['url' => $request->url]);

		return $shortedUrl->id;
	}
}

Route

  • 請事先移除預設的其它路由
<?php

// routes/web.php
use App\Http\Controllers\ShorterController;

Route::post('/', ShorterController::class)->name('shorter');

設計 API:重新導向使用者

  • HTTP GET,以路由參數的方式重新導向用戶

Controller

$ php artisan make:controller RedirectController
<?php

// app/Http/Controllers/RedirectController.php

use Illuminate\Support\Facades\Redirect;

class RedirectController extends Controller
{
	public function __invoke(int $id)
	{
		$url = Url::find($id)->url;

		return redirect()->to($url);
	}
}

Route

<?php

// routes/web.php

Route::post('/', 'ShorterController')->name('shorter');
Route::get('/{id}', 'RedirectController')->name('redirector');

上一篇
一週回顧
下一篇
短網址服務(Part2)
系列文
Laravel 8: For Beginners14

尚未有邦友留言

立即登入留言