# Laminas框架-協作筆記
###### tags: `Laminas`
### Route
- URL 架構

- 路由設定
> 請在專案的 module/config/module.config.php 設定
- 基本架構設定
```
'<route_name>' => [
'type' => '<route_type_class>',
'priority' => <priority>,
'options' => [
'route' => '<route>',
'defaults' => [
//...
],
],
]
```
- 基本架構設定實例
> URL : *http://主機名/Module名稱/*
> 因 **Module名稱** 後面沒有帶任何路徑,所以會讀取 **defaults**的內容,且 **action** 是讀取Controller裡的 ***updateData()***
```
'module-example' => [
'type' => Literal::class,
'options' => [
'route' => '/module-example',
'defaults' => [
'module' => 'module-example',
'controller' => Controller\IndexController::class,
'action' => 'updateData',
],
]
]
```
- 含子路由架構設定
```
'<route_name>' => [
'type' => '<route_type_class>',
'priority' => <priority>,
'options' => [
//...
],
'child_routes' => [
// Add child routes here.
// ...
]
]
```
- 含子路由架構設定實例
> - 以下路由規則為通則,可設計狀況去改變路由設定
> - URL : http://主機名/Module名稱/[控制器名稱/Action名稱/參數]
> - URL內的 **"[]"** 代表可帶或可不帶入路徑,則 ***childroutes*** 內容則是定義子路由的內容
> - 如沒帶入任何子路由(或者只帶Controller名稱),則會讀取 ***"option/defaults"*** 內的 Action 內容
> - 因 **Module名稱** 後面可以帶任何路徑片段,所以會讀取 **child_routes**的內容,但 **controller**、**action**、**id** 是則依路徑片段讀取對應的專案內src資料夾內的Controller,及該Controller內的Action或Id等參數。
> - 控制器名稱通常會在定義一個別名,實際帶入URL則為該別名 (定義內容下則說明)
> - 子路由設定內容的 ***"option/constraints"*** 則是設定 **controller**、**action** 的命名規則
```
'module-example' => [
'type' => Literal::class,
'options' => [
'route' => '/module-example',
'defaults' => [
'module' => 'module-example',
'controller' => Controller\IndexController::class,
'action' => 'updateData',
],
],
'may_terminate' => true,
'child_routes' => [
'default' => [
'type' => Segment::class,
'options' => [
'route' => '[/:controller][/:action][/:id]',
'constraints' => [
'controller' => '[a-zA-Z][a-zA-Z0-9_-]*',
'action' => '[a-zA-Z][a-zA-Z0-9_-]*'
],
'defaults' => []
]
]
]
]
```
- Controller設定實例
> - ***aliases*** 內則是設定控制器的別名
> - 如有新增加的controller依序往下增加,則路由位置為: http://主機名/Module名稱/new-one/[Action名稱/參數]
```
'controllers' => [
'factories' => [
Controller\IndexController::class => BaseFactory::class,
Controller\NewOneController::class => BaseFactory::class,
],
'aliases' => [
'sign-up-index' => Controller\IndexController::class,
'new-one' => Controller\NewOneController::class,
]
]
```
### 資料庫處理
#### 資料表規劃、比對、更新
- 規劃好關聯式資料表後,需更新本地專案的 ***"db/db.mwb"*** 到遠端 對應的目錄
- 在遠端執行檔案輸出,並下載更新的Entity到本地對應的位置且覆蓋
> - Entity位置 : 專案/data/temp/更新的Entity
> - 指令 : sudo docker exec -ti "容器名稱" bin/export.sh
- 複製本地更新的Entity檔案到本地的 ***"專案/Base/src/Entity"*** 內並覆蓋
- 遠端比對資料庫:
> - 指令 : sudo docker exec -ti "容器名稱" bin/cli.sh migrations:diff
> - 會在遠端的 ***"data/migrations"*** 產生一個新的版本檔案,如下圖:
> 
- 遠端資料庫寫入:
> - 指令 : sudo docker exec -ti "容器名稱" bin/cli.sh migrations:migrate
> - 
## Doctrine ORM
### CRUD 功能實作說明
> - 以 "share-doc" 專案的 "course-demo" 分支內容做為案例參考
> - 建議專案 git clone 下來後,改名成新的專案,方便作參考比對
> - 實作目標是建立公告欄,對應的資料表為 ***"News"***,此Module會新增兩種功能頁面: **公告欄的列表** 、 **公告欄的留言新增/編輯頁面**
> - 權限等級有兩種 :
### 資料表更新
- 請先實作 **"資料庫處理"** 步驟,並確認需新增或修改的資料表已更新!
### 新增Module的初始設定
- 專案的新增Module設定
> - 此設定檔案為: *專案/config/modules.config.php*
> - 新增 ***"News"*** 字串至 ***return*** 的內容內
> 
- autoload的內容新增
> - 此設定檔案為: *專案/compose.json*
> - 新增 ***"News\\": "module/News/src/"*** 字串至 ***autoload/psr-4*** 的內容內
> - 新增完後需更新遠端的compose設定,請在終端機執行指令 "***sudo dokcer exec -ti share-docphp1 composer dump-autoload***",更新設定
> 
### Module架構建置
- 建置一個 ***"News"*** 的Module,架構如下:
> - 目前為空架構,加上一些Module的設定檔案,可從其他Module的對應檔案複製到此專案內
> - 需複製的基本設定檔案 : ***"專案/config/module.config.php"***、 ***"專案/src/Module.php"***
> 
- Module設定更改如下:
> - ***"module.config.php"***:
> 命名空間、路由(Route)相關、控制器(Controller)的設定
> 
>
> - ***"module.config.php"***:
> 只需改命名空間即可,其他請先用預設即可
> 
### Controller與View的新增
- Controller的新增
> - 新增架構如下 :
> - 新增兩功能所需的Controller
> 
> - 每個空的Controller的基本寫法
> 
- View的新增
> - 新增架構如下 :
> - 因Module新增兩個controller、所以需再新增兩個對應的子資料夾 : ***admin*** 、***index***
> - 預計新增 ***action*** 的關係對應請參考下圖
> 
> - 每個view檔案(twig格式)的內容請如下圖新增即可:
> 
### ACL的設定(權限設定)
- acl.global.php 設定
- 修改檔案位置
> ***"專案/config/autoload/acl.global.php"***
>
- 現有系統角色
> 目前只會用到 **"系統管理員"** 、 **"訪客"** 兩角色
> 
- 資源設定
> 需為這兩角色設定可以讀取的資源,設定如下圖說明
> 
### 取消登入認證的cache(測試環境)
- 全域變數設定
- 修改檔案位置
> ***"專案/config/autoload/global.php"***
- 新增"is_cached"參數,並設為false
> 
- 登入認證取消Cache
- 登入是由 ***"專案/module/User/src/Controller/SignController.php"*** 執行
- 實際修改檔案位置
> ***"專案/module/Base/src/Controller/Plugin/AclPlugin.php"***
- 取消Cache
> 在doAuthorization() 內加上以下判斷,請參考下圖
> 
### 訪客訪問頁的實作
- 撰寫 ***IndexController.php***
> 檔案位置 : ***專案/module/News/src/Controller*** 內
- 需引入相關所需套件、命名空間需正確
- 登入者資訊需正確登入才能取得
- 將資料置入到需回傳的ViewModel物件

- 撰寫 ***index.twig***
> 檔案位置 : ***專案/module/News/view/news/index*** 內
- 透過twing語法,寫入繼承的view框架
- 透過twing語法,印出從Controller取得的資料

### 公佈欄列表頁的實作
- 撰寫 ***AdminController.php***
> 檔案位置 : ***專案/module/News/src/Controller*** 內
- *indexAction()* 實作內容 : 列表資料存取-邏輯處理
> 
- 撰寫 ***index.twig***
> 檔案位置 : ***專案/module/News/view/news/admin*** 內
- 透過twing語法,寫入繼承的view框架
- 在這個view內建立表單及印出從Controller取得的data資料
> 
- 在inline 區塊內,寫入編輯、刪除按鈕的點擊觸發事件
> 
### 公佈欄編輯的實作
- 撰寫 ***NewsForm.php***
> 檔案位置 : ***專案/module/News/src/Form*** 內
> 為 ***edit.twig*** 內會使用的Form表單的設定皆在此
> - 先新增以下資料夾與檔案
> 
> - 在 ***"NewsForm.php"*** 內先建立好建構式等,並建議從MySQL Workbranch 內 EER Diagram 複製 SQL出來並貼上到程式內參考
> 
> - 在建構式內建立與表單標籤對應的方法,請參考下圖方式
> - 並在建構式外建立一個表單過濾的相關方法: ***"addInputFilter()"***
> ※相關官方文件參考 : [Form Element](https://docs.laminas.dev/laminas-form/element/element/)
> ※相關官方文件參考 : [Inputfilter](https://docs.laminas.dev/laminas-inputfilter/intro/)
> 
- 撰寫 ***AdminController.php***
> 檔案位置 : ***專案/module/News/src/Controller*** 內
>
- *updateAction()* 實作內容 : 編輯公告欄資料-邏輯處理
> (待編輯...)
- *deleteAction()* 實作內容 : 刪除公告欄資料-邏輯處理
> (待編輯...)
- 撰寫 ***edit.twig***
> 檔案位置 : ***專案/module/News/view/news/admin*** 內
> (待編輯...)
#### 參考連結
> 用法A:QueryBuilder
> [Query](https://www.doctrine-project.org/projects/doctrine-orm/en/2.7/reference/dql-doctrine-query-language.html)
> 用法B:Entity
> [Entity](https://www.doctrine-project.org/projects/doctrine-orm/en/2.7/reference/query-builder.html)