2021年3月17日 星期三

PHP laravel-admin grid客製化自行定義

基本設定可參考此連結:https://laravel-admin.org/docs/zh/1.x/model-grid-custom-actions

從版本1.7.3開始grid的操作就變成下拉選項,但我並不需要編輯、顯示、刪除等功能,反而是要增加一個按鈕可以操作ajax,而且我還需要在ajax.data多傳一個額外的參數進去,所以決定模仿$actions->add(new Replicate)的方式,自己另外寫一個。

首先我們先下個指令增加RowAction的操作,我們可以將資料夾名稱對應所使用的Controller Name,例如我現在新增的RowAction是要對應ProductController,那麼路徑就設成Product\\XXXX,以後管理起檔案來才方便。

php artisan admin:action Product\\AddCart --grid-row --name="購物車"

如果是第一次新增,app/Admin會多增加一個叫Actions的資料夾,底下就是我們剛剛新增的Product/AddCart.php。

接著我們開始撰寫程式,我這次是想要在grid裡新增一個button,可以讓我直接將商品丟入購物車中。

<?php

namespace App\Admin\Actions\Product;

use App\Models\Cart;
use Encore\Admin\Actions\RowAction;
use Illuminate\Database\Eloquent\Model;
use Illuminate\Http\Request;
use Encore\Admin\Facades\Admin;

class AddCart extends RowAction
{
    public $name = '購物車';
    
    public function handle(Model $model, Request $request)
    {
        // $model ...
        $cart = new Cart();
        $cart->sale_id = $request->get('_saleid');
        $cart->product_id = $this->getKey();
        $cart->sale_amount = 1;
        ...
        $cart->save();
        return $this->response()->success('選購成功');
    }

}

然後找到要使用此RowAction的ProductController.php,因為我們沒有要直接使用$actions->add(new Replicate),所以需要自行編寫javascript,其實也不難,直接copy $actions->add(new Replicate)所產生的javascript文字來改寫就好。

提供一下我寫的grid column部份

$grid->column('id','操作')->display(function ($id) {
    return "<a class='btn btn-s btn-success btn-add-to-cart' data-_key='{$id}'><i class='fa fa-cart-plus'></i> 選購</a>";
});

data-_key一定要照著這麼寫哦,不然AddCart.php裡的$this->getKey()會取不到值。

接著我們來產生javascript吧!在Controller底下增加一個function,因為最底下有個process.then(actionResolver).catch(actionCatcher),所以我們必須要補上actionResolver跟actionCatcher的定義,因為我有個值是在URL上,所以寫了一個取params的javascript,然後我增加了一個ajax.data→_saleid: urlParams.get('saleid'),如果使用自行定義是沒辦法增加data的,又或許可以?我沒找到相關的範例就是了。

use Encore\Admin\Admin;
    
    protected function iScript() {
        $script = <<<EOT
        var actionResolver = function (data) {

            var response = data[0];
            var target   = data[1];
                
            if (typeof response !== 'object') {
                return $.admin.swal({type: 'error', title: 'Oops!'});
            }
            
            var then = function (then) {
                if (then.action == 'refresh') {
                    $.admin.reload();
                }
                
                if (then.action == 'download') {
                    window.open(then.value, '_blank');
                }
                
                if (then.action == 'redirect') {
                    $.admin.redirect(then.value);
                }
                
                if (then.action == 'location') {
                    window.location = then.value;
                }
            };
            
            if (typeof response.html === 'string') {
                target.html(response.html);
            }

            if (typeof response.swal === 'object') {
                $.admin.swal(response.swal);
            }
            
            if (typeof response.toastr === 'object' && response.toastr.type) {
                $.admin.toastr[response.toastr.type](response.toastr.content, '', response.toastr.options);
            }
            
            if (response.then) {
              then(response.then);
            }
        };
        
        var actionCatcher = function (request) {
            if (request && typeof request.responseJSON === 'object') {
                $.admin.toastr.error(request.responseJSON.message, '', {positionClass:"toast-bottom-center", timeOut: 10000}).css("width","500px")
            }
        };
        var urlParams = new URLSearchParams(window.location.search);
        $('.btn-add-to-cart').off('click').on('click', function() {

            var data = $(this).data();
            var target = $(this);
            Object.assign(data, {"_model":"App_Models_Product"});
            
                    var process = new Promise(function (resolve,reject) {
                
                Object.assign(data, {
                    _token: $.admin.token,
                    _action: 'App_Admin_Actions_ProductSale_AddCart',
                    _saleid: urlParams.get('saleid'),
                });
            
                $.ajax({
                    method: 'POST',
                    url: '../_handle_action_',
                    data: data,
                    success: function (data) {
                        resolve([data, target]);
                    },
                    error:function(request){
                        //reject(request); debug用
                        reject('選購失敗');
                    }
                });
            });
    
            process.then(actionResolver).catch(actionCatcher);
        });
EOT;
        Admin::script($script);
    }

完成後,我們回到grid裡加上剛剛寫的script function。

protected function grid()
{
    $this->iScript();
    $grid = new Grid(new Product());
    ...
}

好了,完成了,下篇要介紹在同個頁面上可以查看目前選購商品的按鈕。


2020年7月23日 星期四

php artisan make小筆記

建立migration
php artisan make:migration create_users_table

編輯結構內容
public function up()
    {
        Schema::create('flights', function (Blueprint $table) {
            $table->increments('id');
            $table->string('name');
            $table->string('airline');
            $table->timestamps();
        });
    }

執行migration
php artisan migrate

mysql to seed

建立model並指定目錄,無指定皆會建立在預設目錄app底下
php artisan make:model /Models/User

建立controller並配合指定目錄下之model,這裡弄了好久,因為一直不成功,想說app目錄中是顯示小寫,就把指令裡的App改為app,原來要大寫才行。
php artisan admin:make UserController --model='App\Models\User'


2020年6月20日 星期六

laravel-admin碎碎念

#20210428 更新
終於讓我找到怎麼在form底下抓取input當前輸入的值了!!!!!
這超重要,對於要寫小複雜rules的我幫助很大。
request()->all()['input_name'];

遇到網站開不起來時...
  1. 先檢查是不是DB連線有問題,連線語法。
    mysql.server start
  2. config改完,.env檔(目錄下方的隱藏檔案)也要重新檢查。
  3. config改完後先執行「php artisan config:cache」再執行「php artisan serve」。

如何建立一個共用函數

欄位輸出前如何加入前置作業,例如:將時間戳記轉成日期格式後輸出至text

台灣身分證檢查
安裝完後,使用方法如下
$form->text('tw_id','身分證')->attribute('maxlength', 10)->rules('tw_id');
錯誤訊息則是在resources/lang/zh-TW找到validation.php,檔案開啟後在最下方加上
'tw_id' => ':attribute 格式錯誤。',
這樣就可以嘍。

checkbox的使用需要在model加上array2string及string2array

擴展laravel-admin裡的admin_users欄位。


2020年4月15日 星期三

Laravel+Laravue for Mac OS

今天要紀錄的主要是Laravue的部份,遇到了好多問題才能順利on起整個模版,拍拍自己,還好堅持住了,沒有放棄不用它。

[laravel安裝]
主要參考來源:https://ithelp.ithome.com.tw/articles/10216204
次要參考來源:https://ray247k.blogspot.com/2018/03/laravel-mac.html

上一篇提到參考了某篇文章最後決定安裝php7.1就是來自第2個參考來源,雖然不知道現在還是不是有一樣的問題,但我怕麻煩,能少一事就少一事。

安裝composer
curl -sS https://getcomposer.org/installer | php 

使用 Composer 下載 Laravel installer
composer global require "laravel/installer"

把$HOME/.composer/vendor/bin目錄放置於環境變數 $PATH裡,這樣系統才能夠找到並正確執行laravel這個指令
export PATH="$PATH:$HOME/.composer/vendor/bin"

然後就能夠建立Laravel的專案了,不過這邊我就不做了,因為下一步要clone laravue的專案下來,直接使用這套模版。

[laravue安裝]
Laravue是一個laravel+vue.js的後台管理系統,因為對vue.js有興趣,找了一陣子才找到這套模版,往後也有打算用在客戶的後台管理系統。
參考來源:https://doc.laravue.dev/guide/#getting-started

因為這套系統會使用node.js,我們要先把node.js安裝起來,我們是透過home-brew來安裝,執行命令前要先確保你的系統已經安裝過home-brow嘍(安裝方式可以參考上一篇文章)
brew install node 

裝完後如果要檢查版本這樣做就行了
node -v
npm -v

接著切換到我要Clone的目錄底下
cd /my/path

下載模版並切換到該專案目錄下
composer create-project tuandm/laravue
cd laravue

接下來都是舉node.js有關的指令
npm install
npm run dev
在執行這兩行指令時我有跳出錯誤,這錯誤我找了超多文章才終於找到真正的解決之道,在這邊也放上來供大家參考。
參考來源:https://npm.community/t/npm-err-cb-never-called-macos/6101
!!錯誤訊息:npm ERR! cb() never called!
這錯誤訊息似乎是與權限有關係,解法如下,我們只要輸入下列指令後再執行上方的指令就能夠完成了。
sudo chown -R $(whoami) ~/.npm

在執行Migration前請我做了幾件事,一個參考了程式中的dbname,先在mariaDB中將DB建立好,然後到.env中修改DB連線,然後我才順利將seed餵進我的DB裡...不然一直跳出錯誤真的很煩呀!
php artisan migrate --seed

你以為這樣終於能順利執行系統了嗎?才沒有!!就在我想說這次總能順利登入系統時…又出現了一個error。
參考文章:https://github.com/tymondesigns/jwt-auth/issues/1729
!!錯誤訊息:\JWT\Signer\Hmac::doVerify() must be an instance of Lcobucci\JWT\Signer\Key
很抱歉,我並沒有把完整的錯誤訊息留下,這是找解法時人家的標題內容,如果你的錯誤訊息也有部份長的一樣,大概都會是相同的解法啦,我稍為了解了一下,這東西要你產生一個key出來才能使用,所以我們只要執行下列指令產出一個key值就能解決了。
php artisan jwt:secret

執行專案
php artisan serve

看到自己終於能夠順利登入模版,眼淚差點沒掉下來,好了!接下來就是要慢慢研究這模版怎麼使用要怎麼改,祝大家好運,我也是。

哦對了,今天在指令處用了不一樣的樣式,其實是copy官方的命令時忘了先去掉樣式就直接貼在日誌上,然後發現好漂亮哦,於是將錯就錯就用哩,呵呵呵。


PHP+Nginx+MariaDB for Mac OS

安裝時參考了很多篇文章,當參考文章的某個步驟寫的太複雜時就會再去找別篇文章參考,反正步驟看起越簡單的就越得我青睞,最後東拼西湊的終於完成安裝,在這裡記錄一下過程以供日後參考。

[安裝home-brew]
參考來源:https://codertw.com/資料庫/18645/
安裝xcode命令列工具
xcode-select --install

檢查當前環境是否最新符合brew執行
brew doctor

home-brew的安裝
ruby -e "$(curl -fsSL https://raw.githubusercontent.com/Homebrew/install/master/install)"

[安裝 Nginx伺服器]
brew install nginx

安裝好後執行下面幾條命了測試一下
# 啟動 nginx服務
sudo nginx
# 重新載入配置|重啟|停止|退出 nginx
nginx -s reload|reopen|stop|quit
#測試配置是否有語法錯誤
nginx -t

啟動後可以在瀏覽器上輸入http://localhost:8080/看看是不是能看到Nginx的首頁哦。

[開機自啟動nginx服務設定]
參考來源:https://juejin.im/post/5c8fb28a6fb9a07103548318
sudo brew services start nginx

[安裝php及php-fpm]
參考來源:https://tecadmin.net/install-php-macos/
因為看了某篇文章(忘了把來源留下),決定這次要安裝php7.1版本,所以找了可以指定版本的語法的來安裝。

Install PHP 7.1
curl -s http://php-osx.liip.ch/install.sh | bash -s 7.1

Verify PHP Installation
export PATH=/usr/local/php5/bin:$PATH 

至於php-fpm在安裝php時即會一併被安裝,因此不需要另外下安裝指令。

啟動php-fpm
sudo php-fpm

[修改nginx.conf及php-fpm.conf]
參考來源:https://www.jianshu.com/p/e6a9dc091296

下方會另外說明如何修改nginx的預設路徑。

修改php-fpm檔案,先執行複製指令
sudo cp /private/etc/php-fpm.conf.default /private/etc/php-fpm.conf

到/private/etc/目錄下找到php-fpm.conf檔打開來找到error_log,內容改成下列內容
error_log = /usr/local/var/log/php-fpm.log

修改nginx檔案,找到/usr/local/etc/nginx/目錄下的nginx.conf檔,因為不想每次都要打:8080,決定將端口改為80port,找到listen 8080後改成80
listen       80;

在location /的地方加上index.php
location / {
root  html;
index  index.html index.htm index.php;
}

找到location ~ \.php$,修改fastcgi_param成下列內容
fastcgi_param  SCRIPT_FILENAME  $document_root$fastcgi_script_name;

號外!!我不想使用預設路徑(/usr/local/var/www/)該怎麼做呢?調整nginx.conf就對哩,找到剛剛的location /及location ~ \.php$,將root  html改成
root   /my/path;

接著到/private/etc/php-fpm.d/底下找到www.conf.default改成www.conf。

如果沒有調整root路徑請在/usr/local/var/www/目錄下新建index.php,如果有請在剛剛填上的路徑資料夾中建立index.php檔,檔案內容為
<?php
echo phpinfo();
?>

重啟nginx及php-fpm的服務
sudo php-fpm restart
sudo nginx -s reload

在瀏覽器中輸入http://localhost可以看到phpinfo的內容就代表安裝成功嘍。

[安裝MariaDB]
參考來源:https://hoyangtsai.github.io/posts/2015/12/09/mac-using-homebrew-install-mariadb/

我得承認MariaDB的安裝過程我是真真切切的忘的差不多了…還忘了當初root密碼是設定什麼?到底什麼時候設定過的?所以大家照著上面的網址做唄,怕誤導了大家就不另外說明了…

另外,提供一下萬一真的忘了root密碼可以參考這篇文章哦。
https://blog.goodjack.tw/2018/02/mariadb-root.html

下一篇會說明Laravel及Laravue(Laravel+Vue)的安裝過程哦,這才是我最想紀錄的。

2020年3月16日 星期一

從Windows將Visual Studio專案移至Mac時出現無法複製pdb檔

參考:https://www.feval.ca/posts/fixing-cs2012/

原因出在我將檔案放在外接式硬碟,而硬碟當初分割成兩個部份,一部份切割成「HFS」格式用來當我的Mac Backup,而另一部份為了要與Windows共用檔案,我切成「FAT」格式來使用,而我的專案就放在FAT格式下的資料夾裡,沒想到是這個原因造成我的專案無法Debug…又學到了一課。

2019年7月3日 星期三

php .htaccess的一些筆記

想控制瀏覽器cache可以透過.htaccess來下手,如下所示。
<IfModule mod_headers.c>
#no cache for html
<FilesMatch "\.(php)$">
Header set Cache-Control "max-age=0, no-cache, no-store, must-revalidate"
Header set Pragma "no-cache"
</FilesMatch>
# a year for image files
<FilesMatch "\.(ico|jpg|jpeg|png|gif|swf)$">
Header set Cache-Control "max-age=31536000, public"
</FilesMatch>
# One month for css and js
<FilesMatch "\.(js|css)$">
Header set Cache-Control "max-age=2628000, public"
</FilesMatch>
</IfModule>
FilesMatch的設定是看副檔名設定,原以為是看瀏覽器的檔案類型,譬如php會顯示為html的類型,結果不是,在這邊紀錄一下,免得下次又忘記。