---
# System prepended metadata

title: laravel 一些解惑 跟注意
tags: [Laravel]

---

# laravel 一些解惑 跟注意 

controller正常瘦身(完整版)(對於用觀察者再調用service 還是直接用 service先用用看決定 ,有人說用觀察雖然看不到,但可以註解)
https://www.youtube.com/watch?v=ShrS3HXwzPg

看看就好 很快
https://hackmd.io/@javck/ByJgF8HRP/%2Fn6HzxQXCRR2hlaTWU_I3sQ

## 使用萬用sql印出
$addSlashes = str_replace('?', "'?'", $query->toSql());
        dd(vsprintf(str_replace('?', '%s', $addSlashes), $query->getBindings()));
        
    小心 這邊where bool會''字串 但一樣能跑


## 合同 vs interface
要記住合約是一個接口，但接口不一定是一個合約


##  Listeners vs jobs vs Notifications
Only Jobs can be scheduled
One of key differences between the Jobs, Listeners and Notifications,

**只有job可以排程
Listeners跟通知都不能**
它們可以被延遲，這意味著Listener或Notification將被推送到隊列中，但稍後會被處理。


## 事件和監聽器 作業和隊列


儘管它們都可以一起工作，但我發現最容易將事件和偵聽器放在一起查看，然後將作業和隊列放在一起查看。

**事件和監聽器**

事件是保存“觸發”數據的對象，Laravel 事件系統在它被觸發時“捕獲”事件對象，然後運行為該特定事件註冊的所有偵聽器。

如果您考慮一下，這類似於異常的工作方式。你拋出一個異常，你可以定義幾個 catch 塊來根據拋出的異常做出反應。在事件和偵聽器的情況下，會拋出一個事件，並且一個或多個偵聽器代表 catch 塊的內容。雖然相似，但事件和偵聽器不是錯誤處理程序，它們只是在概念上有相似之處。

**作業和隊列**

我認為考慮這些的最好方法就像銀行的一條線。線路本身就是隊列，線路中的每個客戶都是一個作業。

為了處理隊列中的作業，您需要命令行進程或守護進程。將在命令行上啟動隊列守護程序視為將新的銀行櫃員添加到可用的銀行櫃員池中。當守護進程可用時，它會向隊列詢問下一個作業，就像銀行出納員要求排隊的下一個人走到窗口一樣。

排隊的每個人都有他們想要完成的特定任務，例如存款或取款。排隊的人需要完成的動作是 Laravel 中的 Worker。


## create的時候 如果有外key
![](https://i.imgur.com/fqyup7Y.png)
直接這樣append就好

https://joansay.blogspot.com/2016/06/php-arraymerge.html


## csrf
當前 session 的 CSRF 口令可以透過 request 的 session 又或者是幫助函式 csrf_token()來取得

```
use Illuminate\Http\Request;

Route::get('/token', function (Request $request) {
    $token = $request->session()->token();

    $token = csrf_token();

    // ...
});
```


為了簡便，你也可以使用 @csrf 這個Blade標籤來生成這個隱藏輸入項:

```
<form method="POST" action="/profile">
    @csrf

    <!-- Equivalent to... -->
    <input type="hidden" name="_token" value="{{ csrf_token() }}" />
</form>
```
預設被定義在 web 中介層群組的 `App\Http\Middleware\VerifyCsrfToken` 中介層，將會自動的驗證請求中的token是否符合存在 session 當中的token。如果符合的話，我們就知道這個請求真的是用戶自己發出的


###  X-XSRF-Token

Laravel 將當前的 CSRF 口令保存在一個 XSRF-TOKEN cookie 中，該 cookie 包含在框架生成的每個回應當中。你可以使用 cookie 值來設置 X-XSRF-TOKEN Header

這個 cookie 主要是作為一種方便使用者的方式發送的，因為一些 JavaScript 框架和函式庫，例如 Angular 和 Axios ，會自動將它的值放入 X-XSRF-TOKEN Header 裡頭

技巧：預設情況下，`resources/js/bootstrap.js` 文件包含的 Axios HTTP 函式庫，會自動為你發送 CSRF 口令 Header。


## 服務 注入 靜態方法
三個比較解惑
https://www.youtube.com/watch?v=q08X7a5VfhE
https://blog.quickadminpanel.com/laravel-when-to-use-dependency-injection-services-and-static-methods/

如果是簡單計算或輔助方法像helper那種,就使用靜態,個人感覺這function是他獨有的,也常會被用到就靜態,如果很複雜,因該遵守SOLID原則,用helper
https://softwareengineering.stackexchange.com/questions/111938/which-is-a-better-practice-helper-methods-as-instance-or-static


靜態方法是無狀態的,不能保存資料
當你要用到這個class很多funtion要調用不同,這樣一直靜態方法不好,不如new一個(這樣也能帶參數進去 因為每次new不同)
(不需要傳參數就用依賴注入 比較方便)(利用type hint的方法注入 原理是反射)

## 簡單分頁
在分頁中，如果您只想擁有“上一個/下一個”鏈接而不是所有頁碼（因此數據庫查詢更少），只需更改paginate()為simplePaginate()：


```
// Instead of 
$users = User::paginate(10);

// You can do this
$users = User::simplePaginate(10);
```
## 刀片指令添加真/假條件
Laravel 8.51 中的新功能：@classBlade 指令用於添加關於是否應添加某些 CSS 類的真/假條件。

before
`<div class="@if ($active) underline @endif">`

now
`<div @class(['underline' => $active])>`

```
@php
    $isActive = false;
    $hasError = true;
@endphp

<span @class([
    'p-4',
    'font-bold' => $isActive,
    'text-gray-500' => ! $isActive,
    'bg-red' => $hasError,
])></span>

<span class="p-4 text-gray-500 bg-red"></span>
```


## redirect()
你redirect()不僅可以給 URL 或特定路由，還可以給特定 Controller 的特定方法，甚至傳遞參數。用這個：

`return redirect()->action('SomeController@method', ['param' => $value]);`
## 向分頁鏈接添加參數

在默認的分頁鏈接中，您可以傳遞附加參數、保留原始查詢字符串，甚至指向特定的#xxxxx錨點。

```
{{ $users->appends(['sort' => 'votes'])->links() }}

{{ $users->withQueryString()->links() }}

{{ $users->fragment('foo')->links() }}
```


## IOC DI contanier bind make interface provider 的綜合理解

**當你要使用一個東西 而這東西有很多樣式,你就這東西的樣式變成接口,然後注入到這個東西裡面,但這東西實現要new兩次 因為接口沒綁定,所以要把這東西變成容器,去註冊,但註冊要記得他有接口,所以要用bind不能用注入的,但這樣會很亂,所以要用provider去管理**

## mvc拆分
https://medium.com/mr-efacani-teatime/laravel%E7%AD%86%E8%A8%98-%E6%A1%86%E6%9E%B6%E8%A8%AD%E8%A8%88%E6%A8%A1%E5%BC%8F-bbf58d101478

## 關於 composer install / composer update / composer require
https://medium.com/@j4demacia/%E9%97%9C%E6%96%BCcomposer-install-update-require-2a9561e714a4

* composer install
安裝此檔案內相依版本的套件,部署一個別人創立的專案時，要安裝vender用的,若無 composer.lock ，則會去照 composer.json 安裝，並生成 composer.lock 。一般是在新創專案時的步驟，寫好 composer.json ， 下 composer install ，這樣的case通常只有一次。
* composer require
添加 package 用。
會去添加安裝的版本，加入相依並紀錄到 composer.json 和 composer.lock
* composer update
更新最新版，最好不要用。

## **request注意**

request是一個 class,但也是個array

雖然平常都是用request用-> , 但array也很好用
->就不能抓到最裡面,但Arr::get就可以
像下面的例子你可以直接看他post or  get裡面有沒有攜帶你要的資料欄位(key)

ex 

```
/**
     * 套用排序.
     */
    public function applyOrderByQuery(Builder $query, ?BaseRequest $request = null): Builder
    {
        return $query->orderBy(
            Arr::get($request, 'sort', 'id'),
            Arr::get($request, 'dir', 'asc')
        );
    }
```
雖然->一樣可以取得嵌套裡面的
但arr::get()可以給預設值

## $request->input() vs $request->get()
input 比較好

input 跟 get都可以給預設值在第二個參數


## query()
https://stackoverflow.com/questions/51517203/what-is-the-meaning-of-eloquents-modelquery
使用 Model::query() 的地方是我需要實例化一個查詢，然後根據請求變量建立條件。
```
$query = Model::query();
if ($request->color) {
    $query->where('color', $request->color);
}
```
可以參考我作品旅人地圖
![](https://i.imgur.com/sBfXV3f.png)



## 找錯誤訊息
https://ithelp.ithome.com.tw/articles/10216835
去 Exceptions/Handler.php 找錯誤訊息

簡單方法在 **render 方法中 加入 dd($exception)**
![](https://i.imgur.com/IHSjQnD.png)

進階方法
```
use Illuminate\Database\Eloquent\ModelNotFoundException;

public function render($request, Exception $exception)
{
    if ($request->expectsJson()) {
        if ($exception instanceof ModelNotFoundException) {
            return response()->json(
                [
                    'error' => '找不到資源'
                ],
                Response::HTTP_NOT_FOUND
            );
        }
    }
    return parent::render($request, $exception);
}
```
**instanceof 用于确定一个 PHP 变量是否属于某一类 class 的实例：**

程式碼解釋，使用者請求回傳JSON 格式，發現有錯誤 ModelNotFoundException 被拋出，因為Model 沒有抓到資料，回傳 404 Not Found 並附上錯誤資訊。
## 不要跑composer update
與 Laravel 無關，但是......永遠不要`composer update`在生產實時服務器上運行，它很慢並且會“破壞”存儲庫。始終`composer update`在您的計算機上本地運行，`composer.lock`向存儲庫提交新內容，並`composer install`在實時服務器上運行。

##  query builder 語法跟 ORM不一樣 
所以最好用一些Where 語法之類的 不要用find

像反白的where找id 用find就會爆炸
![](https://i.imgur.com/jmyn0gB.png)


## switch 的default == else 

![](https://i.imgur.com/FYCVSzK.png)


##   RESTful API
https://hackmd.io/@8irD0FCGSQqckvMnLpAmzw/Hk8QeMNLz?type=view

## all() get()
User::all()并User::get()会做同样的事情。

all()是一种静态的方法Eloquent\Model。它所做的就是创建一个新的查询对象并调用get()它。使用时all()，无法修改所有执行的查询（除非可以通过将它们作为参数传递来选择要选择的列）。
`最大差別`
all多   query() 
        file()

get()是Eloquent\Builder对象的一种方法。如果需要修改查询，例如添加where子句，那么必须使用get()。例如，User::where('name', 'David')->get();。




## model調用 has where差別

has抓關聯

where抓自己屬性


##  model要修改屬性注意 關鍵字 collection與stdClass 這邊非常重要(好像可以用[0]這種陣列去取 有成功過)
![](https://i.imgur.com/UnSK852.png)





collection不可修改 不可取屬性(若要取屬性)有三種方法(在下方)

    第一部分
dd出來時看左上角
左上角的要對上 ex App\comment 可以進行修改
如果是 app\...\collection 集合的話 不管怎樣都修改不了

first() last() find() firstOrFail() findOrFail()
最屌寫法加上random()超猛 seeder必用
這些可直接修改

    第二部分

```
使用時，get()您會得到一個收藏。在這種情況下，您需要對其進行迭代以獲取屬性：

@foreach ($collection as $object)
    {{ $object->title }}
@endforeach
或者，您也可以通過索引獲得對象之一：

{{ $collection[0]->title }}
或從集合中獲取第一個對象：

{{ $collection->first() }}
當您使用find()或first()獲得對象時，可以使用以下簡單方法獲取屬性：

{{ $object->title }}
```

https://stackoverflow.com/questions/41366092/property-title-does-not-exist-on-this-collection-instance



## config有改動
 php artisan config:cache

## migrate有改動或seeder 之類的 只要表有動到

composer dump-autoload 

## 這個沒用過 修改資料欄位
要修改資料欄位，首先要安裝：
```
composer require doctrine/dbal
```

接著一樣針對某張資料表新增 migration，
修改指定資料表內的資料欄位：
```
public function up()
{
    Schema::table('news', function (Blueprint $table) {
        $table->string('title', 50)->nullable()->change();
    });
}
```

## a連接form 要給id 這樣才不會傳送第一個表單
```
<a class="btn btn-danger btn-circle btn-sm" href="#" onclick="event.preventDefault();
                  document.getElementById('destroy_form_**{{ $a->id }}**').submit();">
                  <i class="fas fa-pen"></i>
                </a>

                <form id="destroy_form_**{{ $a->id }}**" action="{{ route('attractions.destroy', ['attraction' => $a->id]) }}"
                  method="POST" class="d-none">
                  @csrf
                  @method('DELETE')
                </form>
```
## laravel用前端框架套件的雷

**config有更動都要 php artisan config:cache**
**表有更動都要composer dump-autoload**
### datatable

如果jquery沒有吃到 加上defer 原因還沒想通 

### laravel裡面用會員alpine會跟vue衝突
解決辦法
把veu關了 在app.js



### 如果資料被編碼 &這種的叫甚麼html...的編碼

可用{!! !!} or <?php ?>


##  requset不能修改 所以都用來當作value


## 當你model 裡面有資料 在另外建立欄位的時候 要nullable() 不然會壞掉


## with error 跟 success
這是一個“神奇”的方法，因為任何對帶有前綴的方法的調用都with將作為閃存數據添加到會話中。所以withError()會在key下添加flash data error；withErrors()會在key下添加flash數據errors；withSuccess()將在鍵下添加閃存數據success；等等


###### tags: `Laravel`