---
# System prepended metadata

title: Laravel 列排序以及分頁範例
tags: [PHP, ' Backend', ' Laravel']

---

---
tags: PHP, Laravel, Backend
---

# Laravel 列排序以及分頁範例

## 安裝`kyslik/column-sortable`
==此包適用於Laravel 5/6/7/8==

### composer
`composer require kyslik/column-sortable`

### 手動安裝(laravel 5.5之前版本)
在`config/app.php`添加服務提供者

```php=
'providers' => [

    App\Providers\RouteServiceProvider::class,

    /*
     * Third Party Service Providers...
     */
    Kyslik\ColumnSortable\ColumnSortableServiceProvider::class,
],
```

### 發佈配置
`php artisan vendor:publish --provider="Kyslik\ColumnSortable\ColumnSortableServiceProvider" --tag="config"`

## 用法

### 在Model中使用

在你想使用排序的`model`使用`Sortable`
，將要使用排序的欄位定義在`$sortable`陣列當中

```php=
<?php

namespace App\Models;

use Kyslik\ColumnSortable\Sortable;

class Product extends Model
{
    use Sortable;

    public $sortable = ['id', 'name', 'created_at', 'updated_at'];

}
```

提醒: `Sortable trait` 為模型添加了 `Sortable` 範圍，因此您可以將其與分頁一起使用。

### 在Blade中

在`laravel Blade`中使用`@sortablelink()`

```php=
@sortablelink('column', 'Title', ['parameter' => 'smile'],  ['rel' => 'nofollow'])
```

1. 第一個參數: 要排序的欄位名稱
1. 第二個參數: 在前端要顯示的名稱
1. 第三個參數: Http GET默認查詢字符串參數`?parameter=smile`
1. 第四個參數: 可以在第 4 個參數中使用自定義 URL 作為 'href' 屬性，查詢字符串將附加到它。此範例會將`rel="nofollow"`附加在`a tag`上

可以省略第二，第三，第四個參數

官方提供可能使用範例與情境

```php=
@sortablelink('name')
@sortablelink('name', 'Username')
@sortablelink('address', trans('fields.address'), ['filter' => 'active, visible'])
@sortablelink('address', trans('fields.address'), ['filter' => 'active, visible'], ['class' => 'btn btn-block', 'rel' => 'nofollow', 'href' => route('my.custom.route')])
```

:::info
可以設置應用於標題（第二個參數）的默認格式功能，默認情況下設置為[`ucfirst`](https://www.php.net/manual/en/function.ucfirst.php)。
:::

### 簡單的配置

`config > columnsortable.php`

表格中有為可排序連結區分類型（數字、數量和 `alpha`），並為每種類型應用不同的類，可以自行新增或修改對應的`icon`

```php=
'columns' => [
    'numeric'  => [
        'rows' => ['created_at', 'updated_at', 'level', 'id'],
        'class' => 'fa fa-sort-numeric'
    ],
    'amount'   => [
        'rows' => ['price'],
        'class' => 'fa fa-sort-amount'
    ],
    'alpha'    => [
        'rows' => ['name', 'description', 'email', 'slug'],
        'class' => 'fa fa-sort-alpha',
    ],
],
```

### Font Awesome(預設的字體類)

安裝[Font-Awesome](https://fontawesome.com/versions)

#### Font Awesome 5

更改正序倒序的`icon`，將配置文件中的後綴類分別從 `-asc/-desc (FA 4)` 更改為 `-up/-down (FA 5)`。
```php=
/* this is FA 5 compatible.
suffix class that is appended when ascending direction is applied */
'asc_suffix'                    => '-up',

/* suffix class that is appended when descending direction is applied */
'desc_suffix'                   => '-down',
```
:::info
如未發布配置文件請參考[發佈配置](#發佈配置)
:::

## 完整範例

### Routes

`Route::get('/products', 'App\Http\Controllers\ProductController@index');`

### Controller

```php=
public function index()
{
    $products = Product::sortable()->paginate(2);
    return view('products', compact('products'));
}
```

### View(包括分頁)

```blade=
@sortablelink('id', '產品ID')
@sortablelink('name', '名稱')
@sortablelink('created_at', '創建日期')

@foreach ($products as $product)
    {{ $product->id }}
    {{ $product->name }}
    {{ $product->created_at }}
@endforeach

{{-- 此為分頁 --}}
{!! $users->appends(\Request::except('page'))->render() !!}
```
:::warning
注意：Blade 識別指令的能力取決於指令本身之前是否有空格 `<tr> @sortablelink('Name')`
:::

### 展示

![](https://i.imgur.com/14eMW7p.gif)

## HasOne / BelongsTo關聯排序
    
### 定義hasOne關聯

要使用關聯排序，需要先在model定義`hasOne()`關聯
```php=
/**
* Get the user_detail record associated with the user.
*/
public function detail()
{
    return $this->hasOne(App\UserDetail::class);
}
```

### 定義BelongsTo關聯

:::info
如果有自引用模型（如評論、類別等）；父表將使用 parent_ 字符串作為別名，有關更多信息，請參閱[issue #60](https://github.com/Kyslik/column-sortable/issues/60)。
:::

```php=
/**
 * Get the user that owns the phone.
 */
public function user()
{
    return $this->belongsTo(App\User::class, parent_id, user_id);
}
```

### 定義`$sortable` 陣列

在兩個模型中定義 $sortable 數組（否則，package使用 Scheme::hasColumn() 這是一個額外的數據庫查詢）

User Model

`public $sortable = ['id', 'name', 'email', 'created_at', 'updated_at'];`

UserDetail Model

`public $sortable = ['address', 'phone_number'];`

### Blade的關聯排序

```php=
@sortablelink('detail.phone_number', 'phone')
@sortablelink('user.name', 'name')
```

:::info
這裡使用的是在模型中定義的關係“名稱”（方法）而不是使用表名稱。
:::

:::warning
不要同時使用兩個不同關係的組合，你會得到關係未定義的錯誤
:::

預設使用`.`做為關聯預設符號，如果`.`不是你想要的可以到配置文件中修改
```php=
'uri_relation_column_separator' => '.'
```

## ColumnSortable overriding (advanced)

可以覆蓋 ColumnSortable 關係功能，基本上您可以編寫自己的連接/查詢並手動應用 orderBy()

範例:
```php=
class User extends Model
{
    use Sortable;

    public $sortable = ['name'];
    ...

    public function addressSortable($query, $direction)
    {
        return $query->join('user_details', 'users.id', '=', 'user_details.user_id')
                    ->orderBy('address', $direction)
                    ->select('users.*');
    }
    ...
```

`controller`中一樣使用`$users = $user->sortable()->paginate(10);`

在`view`中`@sortablelink('address')`

## 捕捉異常try catch
`ColumnSortableException`使用三個代碼`（0、1、2）`拋出自定義異常 。

**代碼 0** 表示`explode()` 無法將URI 參數“排序”分解為兩個值。例如：`sort=detail..phone_number` - 生成大小為 3 的數組，這會導致package 拋出代碼為 0 的異常。

**代碼 1** 表示 `$query->getRelation()` 方法失敗，這意味著關聯名稱無效（不存在，未在模型中聲明）。

**代碼 2** 表示通過排序參數提供的關係不是 hasOne 的實例。

捕捉異常範例：

```php=
try {
    $users = $user->with('detail')->sortable(['detail.phone_number'])->paginate(5);
} catch (\Kyslik\ColumnSortable\Exceptions\ColumnSortableException $e) {
    dd($e);
}
```

[column-sortable](https://github.com/Kyslik/column-sortable)