瀏覽分類:

程式設計

419 Laravel 踩坑紀錄

Laravel 8

如果你已經想竟辦法刪除所有session 或是任何快取,不管是登入、註冊…永遠都出現 419 畫面,請確認一下你的.env 檔案中,SESSION_DOMAIN 是不是與你的網址相符。

Victor 更改了開發環境的設定,導致我卡了一整天,在此紀錄一下,假設你的網址設定 langlangthing.com 請將.env 檔案修改如下。

SESSION_DOMAIN=langlangthing.com

祝福您早入脫離此坑

SQL語法替換部分字串

版本 PostgreSQL 11

UPDATE 
   table_name
SET 
   path = REPLACE (
      path,
     'http://',
     'https://'
   );

製作浪浪的事認養平台時,有時候因為需要整理資料,會用到這個SQL因此紀錄在此,由於它會更新到資料,謹慎使用。

如上SQL語法表示 table_name 資料表,將path 欄位中找到http:// 替換成 https://

Laravel 輔助函數 – Array篇

以下對每個方法做自我理解的解釋,皆會擷取官網範例,更佳釐清方法用法。

陣列

Arr::accessible 檢查參數是不是陣列或Collection

use Illuminate\Support\Arr;
use Illuminate\Support\Collection;

$isAccessible = Arr::accessible(['a' => 1, 'b' => 2]);

// true

$isAccessible = Arr::accessible(new Collection);

// true

$isAccessible = Arr::accessible('abc');

// false

$isAccessible = Arr::accessible(new stdClass);

// false

Arr::add([array],[key],[value]) 陣列中如果第二個傳入參數key值,如果「不存在」或 key 的值為 null 寫入陣列

use Illuminate\Support\Arr;
use Illuminate\Support\Collection;

$isAccessible = Arr::accessible(['a' => 1, 'b' => 2]);

// true

$isAccessible = Arr::accessible(new Collection);

// true

$isAccessible = Arr::accessible('abc');

// false

$isAccessible = Arr::accessible(new stdClass);

// false

Arr::collapse 將多個陣列合併成一個

use Illuminate\Support\Arr;

$array = Arr::collapse([[1, 2, 3], [4, 5, 6], [7, 8, 9]]);

// [1, 2, 3, 4, 5, 6, 7, 8, 9]

Arr::crossJoin 這叫笛卡兒積,返回所有陣列

use Illuminate\Support\Arr;

$matrix = Arr::crossJoin([1, 2], ['a', 'b']);

/*
    [
        [1, 'a'],
        [1, 'b'],
        [2, 'a'],
        [2, 'b'],
    ]
*/

$matrix = Arr::crossJoin([1, 2], ['a', 'b'], ['I', 'II']);

/*
    [
        [1, 'a', 'I'],
        [1, 'a', 'II'],
        [1, 'b', 'I'],
        [1, 'b', 'II'],
        [2, 'a', 'I'],
        [2, 'a', 'II'],
        [2, 'b', 'I'],
        [2, 'b', 'II'],
    ]
*/

Arr::divide 陣列返回一個二維陣列,將key 以及 value 拆成兩個陣列,如下範例

use Illuminate\Support\Arr;

[$keys, $values] = Arr::divide(['name' => 'Desk']);

// $keys: ['name']

// $values: ['Desk']

Arr::dot 函數會把多為陣列中的key 平鋪成一為陣列,新的陣列將使用「.」符號來表示階層

use Illuminate\Support\Arr;

$array = ['products' => ['desk' => ['price' => 100]]];

$flattened = Arr::dot($array);

// ['products.desk.price' => 100]

Arr::except 移除某個鍵值元素,如下範例將price刪除

use Illuminate\Support\Arr;

$array = ['name' => 'Desk', 'price' => 100];

$filtered = Arr::except($array, ['price']);

// ['name' => 'Desk']

Arr::exists 如下所示,檢查陣列中是否有 name 或 salary 鍵值的存在

use Illuminate\Support\Arr;

$array = ['name' => 'John Doe', 'age' => 17];

$exists = Arr::exists($array, 'name');

// true

$exists = Arr::exists($array, 'salary');

// false

Arr::first 返回陣列第一個元素

use Illuminate\Support\Arr;

$array = ['name' => 'John Doe', 'age' => 17];

$exists = Arr::exists($array, 'name');

// true

$exists = Arr::exists($array, 'salary');

// false

Arr::flatten 將多為陣列的值全部取出,並且平鋪成一維陣列

use Illuminate\Support\Arr;

$array = ['name' => 'John Doe', 'age' => 17];

$exists = Arr::exists($array, 'name');

// true

$exists = Arr::exists($array, 'salary');

// false

Arr::forget 傳入一個陣列以及字串,字串使用「.」的方式表階層,將陣列中的對應階層移除。

use Illuminate\Support\Arr;

$array = ['products' => ['desk' => ['price' => 100]]];

Arr::forget($array, 'products.desk');

// ['products' => []]

Arr::get 傳入一個陣列以及字串,字串使用「.」的方式表示階層,用這樣的方式方面取出對應的值以可以指令預設值。

use Illuminate\Support\Arr;

$array = ['products' => ['desk' => ['price' => 100]]];

$price = Arr::get($array, 'products.desk.price');

// 100

$discount = Arr::get($array, 'products.desk.discount', 0);

// 0

Arr::has 函數使用「.」方式表示陣列階層,確認陣列中是否有存在該階層的值,可以一比對兩個,「皆存在」才會顯示 true。

use Illuminate\Support\Arr;

$array = ['product' => ['name' => 'Desk', 'price' => 100]];

$contains = Arr::has($array, 'product.name');

// true

$contains = Arr::has($array, ['product.price', 'product.discount']);

// false

Arr::hasAny 如上檢查陣列是否有對應的鍵值存在,「任一個」存在就回傳 true

use Illuminate\Support\Arr;

$array = ['product' => ['name' => 'Desk', 'price' => 100]];

$contains = Arr::hasAny($array, 'product.name');

// true

$contains = Arr::hasAny($array, ['product.name', 'product.discount']);

// true

$contains = Arr::hasAny($array, ['category', 'product.discount']);

// false

Arr::isAssoc 判斷陣列的key 有設定自訂鍵值,如果為預設的鍵值將回傳false

use Illuminate\Support\Arr;

$isAssoc = Arr::isAssoc(['product' => ['name' => 'Desk', 'price' => 100]]);

// true

$isAssoc = Arr::isAssoc([1, 2, 3]);

// false

$isAssoc = Arr::isAssoc(["0" => 'a', "1" => 'b', "2" => 'c'])); 

// false

$isAssoc = Arr::isAssoc(["1" => 'a', "0" => 'b', "2" => 'c'])); 

// true

$isAssoc = Arr::isAssoc(["a" => 'a', "b" => 'b', "c" => 'c'])); 

// true

Arr::last 回傳滿足指定條件的最後一個元素值,如下所示200與300接大於等於150回傳最後一個符合結果300,已可指定預設值,如果沒有找到回傳預設值。

use Illuminate\Support\Arr;

$array = [100, 200, 300, 110];

$last = Arr::last($array, function ($value, $key) {
    return $value >= 150;
});

// 300

$default = 0;

$last = Arr::last($array, function ($value, $key, $default) {
    return $value >= 301;
});

// 0

Arr::only 處理陣列是如果只要某幾個元素,可以一個陣列,並且帶入需要的key值即可得到只有這幾個結果的陣列

use Illuminate\Support\Arr;

$array = ['name' => 'Desk', 'price' => 100, 'orders' => 10];

$slice = Arr::only($array, ['name', 'price']);

// ['name' => 'Desk', 'price' => 100]

Arr::pluck 這個Victor我還蠻常使用的,可以在複雜的階層陣列中,找出某個位置的值,如下找出developer底下的name的key值,回傳全部的陣列。

use Illuminate\Support\Arr;

$array = [
    ['developer' => ['id' => 1, 'name' => 'Taylor']],
    ['developer' => ['id' => 2, 'name' => 'Abigail']],
];

$names = Arr::pluck($array, 'developer.name');

// ['Taylor', 'Abigail']

也可以如下範例所示將developer的id設定對應的key值。

$names = Arr::pluck($array, 'developer.name', 'developer.id');

// [1 => 'Taylor', 2 => 'Abigail']

Arr::prepend 元素存入陣列的第一個位置

use Illuminate\Support\Arr;

$array = ['one', 'two', 'three', 'four'];

$array = Arr::prepend($array, 'zero');

// ['zero', 'one', 'two', 'three', 'four']

亦可指定鍵值並插入陣列的第一個位置

use Illuminate\Support\Arr;

$array = ['price' => 100];

$array = Arr::prepend($array, 'Desk', 'name');

// ['name' => 'Desk', 'price' => 100]

Arr::pull 取得需要的元素,並刪除元陣列的該元素,如下所示,將key 等於name回傳,並將陣列內的name元素刪除。

use Illuminate\Support\Arr;

$array = ['name' => 'Desk', 'price' => 100];

$name = Arr::pull($array, 'name');

// $name: Desk

// $array: ['price' => 100]

$value = Arr::pull($array, $key, $default);  // 可以設定不存在時,返回預設值,原陣列不改變

Arr::query 將陣列的內容,轉為查詢的字串,就是網址後面常常看到的query。

use Illuminate\Support\Arr;

$array = ['name' => 'Taylor', 'order' => ['column' => 'created_at', 'direction' => 'desc']];

Arr::query($array);

// name=Taylor&order[column]=created_at&order[direction]=desc

Arr::random 隨意取出陣列中的一個值

use Illuminate\Support\Arr;

$array = [1, 2, 3, 4, 5];

$random = Arr::random($array);

// 4 - (retrieved randomly)

Arr::set 傳入三個參數,預計修改的陣列、字串、值,可以在陣列中,依照中間傳入的字串,格式使用「.」的方式再多維陣列中加入元素。

use Illuminate\Support\Arr;

$array = ['products' => ['desk' => ['price' => 100]]];

Arr::set($array, 'products.desk.price', 200);

// ['products' => ['desk' => ['price' => 200]]]

Arr::shuffle 隨機排序陣列內的元素

use Illuminate\Support\Arr;

$array = Arr::shuffle([1, 2, 3, 4, 5]);

// [3, 2, 5, 1, 4] - (generated randomly)

Arr::sort 陣列正序排序

use Illuminate\Support\Arr;

$array = ['Desk', 'Table', 'Chair'];

$sorted = Arr::sort($array);

// ['Chair', 'Desk', 'Table']

亦可以指定使用某個key做排序。

use Illuminate\Support\Arr;

$array = [
    ['name' => 'Desk'],
    ['name' => 'Table'],
    ['name' => 'Chair'],
];

$sorted = array_values(Arr::sort($array, function ($value) {
    return $value['name'];
}));

/*
    [
        ['name' => 'Chair'],
        ['name' => 'Desk'],
        ['name' => 'Table'],
    ]
*/

Arr::sortRecursive 有點不太知道用意,稍後再補~

use Illuminate\Support\Arr;

$array = [
    ['Roman', 'Taylor', 'Li'],
    ['PHP', 'Ruby', 'JavaScript'],
    ['one' => 1, 'two' => 2, 'three' => 3],
];

$sorted = Arr::sortRecursive($array);

/*
    [
        ['JavaScript', 'PHP', 'Ruby'],
        ['one' => 1, 'three' => 3, 'two' => 2],
        ['Li', 'Roman', 'Taylor'],
    ]
*/

Arr::where 過濾陣列,寫入特定過濾條件過濾

use Illuminate\Support\Arr;

$array = [100, '200', 300, '400', 500];

$filtered = Arr::where($array, function ($value, $key) {
    return is_string($value);
});

// [1 => '200', 3 => '400']

Arr::wrap 將值轉為陣列,如果原本已經是陣列將不會有任何變化。

use Illuminate\Support\Arr;

$string = 'Laravel';

$array = Arr::wrap($string);

// ['Laravel']

如果給定的值為 null

use Illuminate\Support\Arr;

$nothing = null;

$array = Arr::wrap($nothing);

// []

data_fill 如果有對應的key值,將元素加入

$data = ['products' => ['desk' => ['price' => 100]]];

data_fill($data, 'products.desk.price', 200);

// ['products' => ['desk' => ['price' => 100]]]

data_fill($data, 'products.desk.discount', 10);

// ['products' => ['desk' => ['price' => 100, 'discount' => 10]]]

亦可使用 「*」 如下所示,將子陣列缺少 products 下一層全部的子陣列,如果缺少price並設定值200,已有的陣列則不改變。

$data = [
    'products' => [
        ['name' => 'Desk 1', 'price' => 100],
        ['name' => 'Desk 2'],
    ],
];

data_fill($data, 'products.*.price', 200);

/*
    [
        'products' => [
            ['name' => 'Desk 1', 'price' => 100],
            ['name' => 'Desk 2', 'price' => 200],
        ],
    ]
*/

data_get


data_set 函數使用「.」符號從多維陣列或物件中根據指定鍵檢索回傳值,亦可以給予預設值,在未找到的情況下回傳預設值。

$data = ['products' => ['desk' => ['price' => 100]]];

$price = data_get($data, 'products.desk.price');

// 100

$discount = data_get($data, 'products.desk.discount', 0);

// 0

亦可以在還數中使用 「*」通配符找尋所有匹配的值

$data = [
    'product-one' => ['name' => 'Desk 1', 'price' => 100],
    'product-two' => ['name' => 'Desk 2', 'price' => 150],
];

data_get($data, '*.name');

// ['Desk 1', 'Desk 2'];

head 返回第一個值

$array = [100, 200, 300];

$first = head($array);

// 100

last 返回最後一個值

$array = [100, 200, 300];

$last = last($array);

// 300

以上就是Laravel操作陣列的函數,後面幾種函數有些與Arr類別相同,差別在於可以不用建立Arr類別的實體,以上提供給讀者參考,Victor使用自己的方式些一遍主要是增加我的印象,最完整的請參考Laravel 官方文件或框架原始碼 Arr類別。

Laravel Queue – 失敗任務處理

版本

Laravel 8


config/queue.php 陣列中 failed 區塊,可以設定失敗任務的連結設定。

'failed' => [
    'driver' => env('QUEUE_FAILED_DRIVER', 'database'),
    'database' => env('DB_CONNECTION', 'mysql'),
    'table' => 'failed_jobs',
],

監聽任務時如果沒有指定任務失敗的次數,任務將會一直嘗試例請在 JOB handle 函數中增加以下程式碼

public function handle()
{
    // 領取任務後的處理程式
}

當執行的時候,將會一直不斷的嘗試執行不會停止,如果指定 --tries 次數,任務會在執行指定的次數之後刪除任務並將任務放置到失敗的任務 failed_job 資料表中,等待確認問題點後,再讓 job 重新執行,確認沒問題後可以重新執行失敗 job 的指令如下,或者可以用 crontab 定時執行。

$ php artisan queue:retry all

這下好了,如果使用者收不到應該收到的信件或其他資訊怎麼辦,我們必續嘗試監聽失敗,在失敗時通知我們立即處理,有兩種方法。

閱讀更多

Laravel 正確的地方寫正確的程式

php artisan 指令有一大堆可以建立的東西,筆記一下並簡單跟大家分享,要寫什麼邏輯應該要寫在什麼地方,已下次我再釐清思緒隨筆寫下來的文字,Victor 日後再找時間值整理。

Model 資料表對應的相關設定

Controller 設定要送給哪一個方法執行

Mail 設定要送的電子郵件,標題、內文、指向哪個模板

Job 收到隊列排隊的項目,拿回來的資料要怎麼處理的邏輯

Service 商業邏輯,協助 Controller,Controller 呼叫這裡的法(須自行新建檔案)

Repository 協助Model,存一些SQL方法給Service 呼叫 (須自行新建檔案)

event 定義這個系統的事件,例如人生中「吃飯前」要洗手,吃飯前就是事件,當這件事情發生以後,可以外加上各種處理。

Notifications 可以設定,這個通知例如「洗手」需要提醒你,可以設定 傳送mail(可以呼叫定義好的Mail 這裡設定通知誰),或寫入資料庫、寄簡訊,各種管道,

migration 程式碼的方式產生資料庫的資料表

factory 撰寫產生資料庫測試的假資料

command 撰寫可以使用 php artisan 自訂的指令,例如需要固定時間執行的程式,就可以把它寫成指令,每天執行,或其他週期時觸發。

test 產生功能測試或單元測試的檔案,這些測試檔案都是用來撰寫測試程式是否正常運作的方法,常與產生假資料的factory 工廠一起使用。

observer 使用model 操作資料庫時,會有各種狀態正在新增、新增完成,每個階段都可以在這個檔案中加上額外的程式,例如觸發某個事件,修改資料表的某個欄位。

seeder 撰寫預設的資料庫資料,例如資料庫內某個資料表必定有台灣的所有縣市資料,可以產生一個對應的seeder寫在裡面,也可已在檔案中撰寫呼叫factory 的程式,填充很多測試的假資料進入。

request 請求時,例如送出一個表單,會有各種欄位,按下確定發送一個請求到伺服器,可以在這邊檢查請求是否符合規定,如果不符合回傳對應訊息,例如:新建動物的請求,可以建立一個StoreAnimalRequet。 更細的rule 在寫在另一篇

resource 請求就會有回應,這就是伺服器處理完的資料,處理完成時要送到客戶端(使用者)時,在做一些格式轉換的處理,並且可以統一輸出,例如動物的個資源,可以建立一個 AnimalResource 經過這個resource 轉換後,單一比動物的資料,可能包含(年齡、性別…)轉換成最後的要顯示的樣子。

Policy 轉門撰寫這個功能有沒有全線做,這裡指的是已具有權限的會員,例如Victor 我已經是某間公司的員工,我有識別證可以感應進入公司,但我有一些區域,不能進去,例如機房、廚房…或是我今天入住的飯店有分樓層管理,我住在6樓 我已經有今天入住的資格,但我的卡片也只能讓我坐電梯到六樓,這種設定就寫在這裡。

middleware 如果你有較大範圍的設定,可以當作過濾所有的請求,也可以撰寫成最後要回傳的訊息,大範圍的加上其他資訊,例如我想要在每一個回傳訊息,加上Victor 設計的API系統資訊。或是在一進入的請求過濾這個請求是不是會員,或是有沒有符合某些條件,例如:是否年買20歲…

listener 這個檔案可能會跟事件搞混、監聽事件因為常常連再一起說,拆開來事件,就像生活中發生的任何事,在中午12點時或鬧鐘響時,可以撰寫對應的動作,例如中午12點這件事件發生,要去吃午餐的程式…那監聽呢?就是剛剛說的不同的事件綁在一起,例如剛剛說12點到吃午餐,綁在一起,也可以在幫重送消息…

exception 可以自訂例外,Laravel 框架原始也有一些自訂的例外ModelNotFoundException 使用Model 的方式去找資料庫的資料,如果沒有找到,送出這個例外,寫程式的人可以對這個例外做攔截,並做相對應的處理,自訂例外可以在裡面撰寫一些log儲存起來,並撰寫要回傳什麼訊息。

component 跟前端View綁在一起,再另外說明

cast 基本上Model 輸出每個欄位都是文字的資料,可以在casts轉換資料的屬性比如說整數int… ,cast 可以自訂自己的轉換方式,並在Model 的cats 屬性設定個類別,因而產生的類別檔案。

以上這些也都只是定義產生出來的檔案都是Class 類別,如果沒有用Laravel 這樣的設計模式也可以參考,簡單把每個職責分得越清楚,維護起來越容易。

如果你是前端看了有一點點霧煞煞,簡單來說可以把它想像成

css 專門寫樣式

js 專門寫互動

但是這是不同程式語言,不過意思差不多或者可以把它想像成較進階的前端工程師會把css分別建立多個scss 專門寫按鈕、layout 、預設的參數… 最後再用工具打包成一個CSS 這樣的道理一樣,整個是伺服器,Laravel 定義了很多PHP 的class 讓你在對應的地方寫對應的程式。

初探 Serverless AWS Lambda

一開始並沒有接觸到Serverless 這個詞,只有聽到AWS Lambda,所以就嘗試使用Lambda 做了微型服務,以下是我的履歷網站網址,最下方聯絡我的部分,就是利用AWS Lambda的服務。

https://resume.vnewin.com/

之前想說要換工作所以做了一個履歷資料網頁,想說讓面試人員可以認識我,簡單介紹一下自己,但跟朋友說要換工作換到現在,過一陣子了,最近終於跟主管說想離職休息一下!

說真的我朋友說我如果沒有遇到大事不會換工作,都不相信我會換,而且我也穩穩地在目前這份工作工作三年了!(這次我第一份工作)

但這一兩年實在很不順,人生方面不是工作,工作一直順順的,直到去年不小心出車禍,太可怕了讓我了解人類的渺小,讓我躺在家裡將近一個月,現在好多了,可能這一兩年真的非常不順,萌生下這個決定的想法,現在我也終於下定決心離職,看來我真的要出大事才會下定決心。

希望一切越來越好,離題了~今天來介紹我做的這一個小功能,履歷網站的聯絡我功能,順便介紹一下Serverless 先從以前開始說起。

我所知道的 主機到 Serverless

剛剛有提到我一開始接觸到這個AWS Lambda名詞,有點忘記哪一個講座了!第一次聽到覺得真的很新奇,AWS把雲端服務更抽象的出來。

以前可能要買一台伺服器主機,然後安裝需要的網站伺服器軟體、資料庫,如果開發PHP就要再裝PHP。

在往後一點,變成可以用租的,有專門公司在幫你顧伺服器,不管是虛擬的主機或是真實主機都由那間公司幫我們處理實體機器的部分。

近期演變到到雲端的部分,也是有虛擬機的技術,例如AWS的EC2,以上就是如何擁有可以運行的主機方法。

大流量架構

從每一台手機都能上網,網路也越來越方便,系統功能也越來越複雜的時代,分工越來越細用來應付這些大流量的情形。

資料庫

先以資料庫的方面來說,資料庫獨立安裝在一台伺服器,讓這一台伺服器的資源全部負責資料庫的運作,當然還有更細部的分工,比如說多一台機器只做讀取,另外一台只做寫入的動作,之間做同步的動作,甚至在資料庫前再加裝一層  Connection Pool 來排隊要進資料庫交易的連線。

不像我一開始學習時,所有服務都裝在同一台伺服器上。

閱讀更多
PostgreSQL LOGO

SQL 如何查詢以「,」分隔的陣列字串

現在有一個陣列 [1,2,3] 把它轉為字串利用「,」做分隔符號(“1,2,3”),並存入資料表中,該如何查詢?

PHP

$arr = array(1,2,3); //陣列
echo implode(",",$arr); // 輸出 字串 "1,2,3"

JavaScript

var array = [1,2,3];

console.log(array.join());
// 輸出 字串 "1,2,3"
閱讀更多

PHP isset()、empty()、is_null()的區別

這三個方法都是來判斷是否為空值或是有沒有宣告變數的方法,比較容易搞混的是 isset()、 empty() 。簡單整理一下這三個差異的筆記。

  • isset() 檢查的變數存不存在
  • empty()檢查的變數內的是否為空
  • is_null():檢查變數是否為null
閱讀更多