iT邦幫忙

第 11 屆 iThome 鐵人賽

DAY 29
1
Software Development

後端基礎PHP+Mysql & Laravel 30日養成計畫系列 第 29

Day 29 Laravel 5.8 會員註冊及登入系統API:Model & Controller

  • 分享至 

  • twitterImage
  •  

在這個範例中,會員註冊之後會得到一組api token,這組token就等同於會員的通行證,要執行他權限內的行為都要先驗證這組token。
管理者可以查看和刪除任一會員的資料,而非管理者只能看到自己的資料; 編輯的話則只有會員自己能夠編輯自己的資料。驗證身份的程序是在中介層(middleware)中執行。

前置作業:去mysql terminal 建立資料庫
新增專案:

$laravel new 專案名稱

Migration & Model

  1. .env改資料庫名稱、密碼 (這邊沒改沒辦法migrate)
  2. 建立資料表
$php artisan make:migration create_tableName_table 
  1. 去migration底下create_tableName_table.php加入要建立的columns,資料型態用php的就好。
    其他可用的資料型態請見官方文件:https://laravel.com/docs/5.8/migrations
public function up() {
		Schema::create('members', function (Blueprint $table) {
			$table->increments('id');
			$table->string('email');
			$table->string('password');
			$table->boolean('isAdmin')->default(0);
			$table->string('api_token');
			$table->timestamps();
		});
	}
  1. 建立Model (Model名稱通常是單數,開頭要大寫)
$php artisan make:model Model名稱

也可以把上一步建立migration和建立model兩個步驟合併成:

$php artisan make:model Model名稱 -m

其所建立的migration和預設table名稱會是model名稱的小寫開頭、複數型態。
例如:model 名稱 -> Car,migration和table名稱->cars
5. 在app的Member中加入內容,fillable裡放的是能insert進table的欄位,欄位名稱要和table的一致。

<?php

namespace App;

use Illuminate\Foundation\Auth\User as Authenticatable;

class Member extends Authenticatable {
	protected $fillable = [
		'email', 'password', 'api_token', 'isAdmin',
	];

}

  1. 在MySQL新增剛剛設定好的table
$php artisan migrate 

就能在MySQL看到建立好的table了。

由於這次要做的是API,因此不會動到views底下的檔案

Controller

需要建立的檔案總共有4個,分別是BaseController、MemberController、LoginController和LogoutController。

BaseController為MemberCOntroller的父類別,回傳response資料及訊息內容的method定義在這裡。
BaseController.php

<?php


namespace App\Http\Controllers;

use Illuminate\Http\Request;
use App\Http\Controllers\Controller as Controller;

class BaseController
{
    public function sendResponse($result, $message)
    {
        $response = [
            'success' => true,
            'data'    => $result,
            'message' => $message,
        ];


        return response()->json($response, 200);
    }

    /**
     * return error response.
     *
     * @return \Illuminate\Http\Response
     */
    public function sendError($error, $errorMessages = [], $code = 404)
    {
        $response = [
            'success' => false,
            'message' => $error,
        ];

        if(!empty($errorMessages)){
            $response['data'] = $errorMessages;
        }


        return response()->json($response, $code);
    }


}

MemberController包含會員資料的CRUD,也就是新增 Create、查看Read、編輯Update、刪除Delete。

動作 HTTP Method function name
查看會員 get index
註冊會員 post store
編輯會員 put update
刪除會員 delete destroy

MemberController.php

<?php

namespace App\Http\Controllers;

use App\Member;
use Illuminate\Support\Facades\Auth;
use Str;
use Illuminate\Http\Request;
use App\Http\Controllers\BaseController as BaseController;
use Validator;

class MemberController extends BaseController
{
    /**
     * Display a listing of the resource.
     * @param \Illuminate\Http\Request $request
     * @return \Illuminate\Http\Response
     */
    public function index()
    {
        $admins = Member::all();
        $members = [
            'mail' =>  Auth::user()->email,
            'password' =>  Auth::user()->password,
        ];
        if (Auth::user()->isAdmin) //是管理者,回傳所有會員資料
            return $this->sendResponse($admins->toArray(), 'Members retrieved successfully.');
        else //不是管理者,回傳該會員自己的資料
            return $members;
    }

    /**
     * Store a newly created resource in storage.
     *
     * @param \Illuminate\Http\Request $request
     * @return \Illuminate\Http\Response
     */
      public function adminStore(Request $request) { //管理者註冊的function
        try {
            $request->validate([ //這邊會驗證註冊的資料是否符合格式
                'email' => ['required', 'string', 'email', 'max:255', 'unique:members'],
                'password' => ['required', 'string', 'min:6', 'max:12'], 
            ]);

            $apiToken = Str::random(10);
            $create = Member::create([
                'email' => $request['email'],
                'password' => $request['password'],
                'isAdmin' => '1',
                'api_token' => $apiToken,
            ]);

            if ($create) {
                return "Register as an admin. Your Token is $apiToken.";
            }

        } catch (Exception $e) {
            sendError($e, 'Registered failed.', 500);

        }

    }
    public function store(Request $request)
    {
        $request->validate([ 
            'email' => ['required', 'string', 'email', 'max:255', 'unique:members'],
            'password' => ['required', 'string', 'min:6', 'max:12'],
        ]);

        $apiToken = Str::random(10);
        $create = Member::create([
            'email' => $request['email'],
            'password' => $request['password'],
            'api_token' => $apiToken,
        ]);

        if ($create)
            return "Register as a normal user. Your api token is $apiToken";
    }

    /**
     * Update the specified resource in storage.
     *
     * @param \Illuminate\Http\Request $request
     * @param \App\Member $members
     * @return \Illuminate\Http\Response
     */
    public function update(Request $request)
    {

        $input = $request->all();
        $validator = Validator::make($input, [ //修改會員資料一樣要驗證是否符合格式
            'email' => ['string', 'email', 'max:255', 'unique:members'],
            'password' => ['string', 'min:6', 'max:12'],
        ]);

        if ($validator->fails()) {
            return $this->sendError('Validation Error.', $validator->errors());
        }
        $member = Auth::user();
        if ($member->update($request->all()))
            return $this->sendResponse($member->toArray(), 'Member updated successfully.');
    }

    /**
     * Remove the specified resource from storage.
     *
     * @param \App\Member $members
     * @return \Illuminate\Http\Response
     */
    public function destroy(Member $members)
    {
        if ( Auth::user()->isAdmin){ //驗證是否為管理者
            if ($members->delete())
                return $this->sendResponse($members->toArray(), 'Member deleted successfully.');
        }
        else
            return "You have no authority to delete";

    }
}
  • MemberController上面的 use app/Member; 是model名字,Laravel是根據這段去對應的table中讀/存取資料
  • Auth::user(),這邊是借用laravel本身內建的會員驗證機制,可以在middleware驗證後拿到member的資料。

會員每次都入都會產生一組新的token,登入成功後,這組token會被存進資料庫,之後的查看、編輯等動作都會驗證這組token來判斷他的身份。
LoginController.php

<?php

<?php

namespace App\Http\Controllers;

use Str;
use App\Member;
use Illuminate\Http\Request;

class LoginController
{
   public function login(Request $request)
   {
       $member = Member::where('email', $request->email)->where('password', $request->password)->first();
       $apiToken = Str::random(10); //隨機產生一組10個英數字組成的字串
       if($member){
           if ($member->update(['api_token'=>$apiToken])) { //更新 api_token
               if ($member->isAdmin)
                   return "login as admin, your api token is $apiToken";
               else
                   return "login as user, your api token is $apiToken";
           }
       }else return "Wrong email or password!";

   }
}

會員登出後,會將剛才登入時產生的token從資料庫中清除,該欄會被'logged out'字串取代。
LogoutController.php

<?php

namespace App\Http\Controllers;

use App\Http\Controllers\Controller;
use Illuminate\Support\Facades\Auth;
use Str;
use App\Member;

class LogoutController extends Controller
{
   public function logout()
   {
       if ( Auth::user()->update(['api_token'=>'logged out'])) { //更新api token
           return "You've logged out";
       }
   }
}

新手常犯錯誤集錦

  • 如果.env裡的檔案有更動過,要重新php artisan serve
  • 每次重新編輯create_tableName後都要重新$php artisn migrate 一次
  • Auth::user()這邊的function 名稱是固定的,不能自行定義
  • toArray()必須要是一個物件才能調用,例如:$result = $request->toArray();
  • 不要隨便把migration刪掉!!否則之後若有需要再建表時會很麻煩

修改資料表欄位

  • 建表
    php artisan migrate
  • 新增table欄位
    php artisan make:migration add_paid_to_table_name --table="table_name"
  • 移除table欄位
    $table->dropColumn('欄位名稱');
  • 復原上一步建立的表
    php artisan migrate:rollback
    若上一步只有新增欄位,則只會復原新增的欄位
  • 重新建表
    php artisan migrate:fresh
    可修改schema欄位,並將原有資料清空。
  • 重新建表2.0
    php artisan migrate:refresh
    fresh和refresh的差別在於: fresh會直接drop 已存在的table,而refresh則會先rollback再建表。
    refresh後可加入表個數的參數,例如:
    php artisan migrate:refresh --step = 3
    rollback最晚建立的3張表,再重建。
  • rollback所有的建表
    php artisan migrate:reset

如何在不動到資料的情況下變更欄位設定?

安裝套件:

composer require doctrine/dbal

新增更改欄位的schema:

php artisan make:migration change_column_table

up function中定義要更改的欄位

    public function up()
    {
        //Schema這邊table method的update是修改欄位,create則是新增欄位
        Schema::table('posts', function (Blueprint $table) { 
            $table->dateTime('created_at')->change();
            $table->dateTime('updated_at')->change();
        });
    }

更改欄位:

php artisan migrate

上一篇
Day 28 MVC架構
下一篇
Day 30 Laravel 5.8 會員註冊及登入系統API: Middelware、Router、 PostMan 測試
系列文
後端基礎PHP+Mysql & Laravel 30日養成計畫36
圖片
  直播研討會
圖片
{{ item.channelVendor }} {{ item.webinarstarted }} |
{{ formatDate(item.duration) }}
直播中

尚未有邦友留言

立即登入留言