---
# System prepended metadata

title: Laminas框架-協作筆記
tags: [Laminas]

---

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

- URL 架構
![](https://i.imgur.com/t1c27e6.png)

- 路由設定

    > 請在專案的 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"*** 產生一個新的版本檔案，如下圖:
> ![](https://i.imgur.com/168HpM4.png)
- 遠端資料庫寫入:
> - 指令 : sudo docker exec -ti "容器名稱" bin/cli.sh migrations:migrate
> - ![](https://i.imgur.com/UQsWQud.png)


## Doctrine ORM

### CRUD 功能實作說明
> - 以 "share-doc" 專案的 "course-demo" 分支內容做為案例參考
> - 建議專案 git clone 下來後，改名成新的專案，方便作參考比對
> - 實作目標是建立公告欄，對應的資料表為 ***"News"***，此Module會新增兩種功能頁面: **公告欄的列表** 、 **公告欄的留言新增/編輯頁面**
> - 權限等級有兩種 : 

### 資料表更新
- 請先實作 **"資料庫處理"** 步驟，並確認需新增或修改的資料表已更新!

### 新增Module的初始設定
- 專案的新增Module設定
> - 此設定檔案為: *專案/config/modules.config.php*
> - 新增 ***"News"*** 字串至 ***return*** 的內容內
> ![](https://i.imgur.com/1Kzs8nA.png)

- autoload的內容新增
> - 此設定檔案為: *專案/compose.json*
> - 新增 ***"News\\": "module/News/src/"*** 字串至 ***autoload/psr-4*** 的內容內
> - 新增完後需更新遠端的compose設定，請在終端機執行指令 "***sudo dokcer exec -ti share-docphp1 composer dump-autoload***"，更新設定
> ![](https://i.imgur.com/zZFKxqu.png)
 
### Module架構建置
- 建置一個 ***"News"*** 的Module，架構如下:
> - 目前為空架構，加上一些Module的設定檔案，可從其他Module的對應檔案複製到此專案內
> - 需複製的基本設定檔案 : ***"專案/config/module.config.php"***、 ***"專案/src/Module.php"***
> ![](https://i.imgur.com/GyTEi9l.png)

- Module設定更改如下:
> - ***"module.config.php"***:
> 命名空間、路由(Route)相關、控制器(Controller)的設定
> ![](https://i.imgur.com/soddl85.png)
> 
> - ***"module.config.php"***:
> 只需改命名空間即可，其他請先用預設即可
> ![](https://i.imgur.com/1CCSWRY.png)

### Controller與View的新增
- Controller的新增
> - 新增架構如下 : 
> - 新增兩功能所需的Controller
> ![](https://i.imgur.com/wpNShnE.png)
> - 每個空的Controller的基本寫法
> ![](https://i.imgur.com/2YrCh8z.png)


- View的新增
> - 新增架構如下 : 
> - 因Module新增兩個controller、所以需再新增兩個對應的子資料夾 : ***admin*** 、***index***
> - 預計新增 ***action*** 的關係對應請參考下圖
> ![](https://i.imgur.com/RRdHiuY.png)
> - 每個view檔案(twig格式)的內容請如下圖新增即可:
> ![](https://i.imgur.com/jmC6amO.png)

### ACL的設定(權限設定)
- acl.global.php 設定
    - 修改檔案位置
    > ***"專案/config/autoload/acl.global.php"***
    > 
    - 現有系統角色
    > 目前只會用到 **"系統管理員"** 、 **"訪客"** 兩角色
    > ![](https://i.imgur.com/PLqjdRK.png)

    - 資源設定
    > 需為這兩角色設定可以讀取的資源，設定如下圖說明
    > ![](https://i.imgur.com/hHzjQym.png)

### 取消登入認證的cache(測試環境)
- 全域變數設定
    - 修改檔案位置
    > ***"專案/config/autoload/global.php"***
    - 新增"is_cached"參數，並設為false
    > ![](https://i.imgur.com/OOpUEmg.png)

- 登入認證取消Cache
    - 登入是由 ***"專案/module/User/src/Controller/SignController.php"*** 執行 
    - 實際修改檔案位置
    > ***"專案/module/Base/src/Controller/Plugin/AclPlugin.php"***

    - 取消Cache
    > 在doAuthorization() 內加上以下判斷，請參考下圖
    > ![](https://i.imgur.com/NHfIMGP.png)

### 訪客訪問頁的實作
- 撰寫 ***IndexController.php***

  > 檔案位置 : ***專案/module/News/src/Controller*** 內
  -  需引入相關所需套件、命名空間需正確
  -  登入者資訊需正確登入才能取得
  -  將資料置入到需回傳的ViewModel物件
  
  ![](https://i.imgur.com/E9Bd5f9.png)

- 撰寫 ***index.twig***
  > 檔案位置 : ***專案/module/News/view/news/index*** 內
  - 透過twing語法，寫入繼承的view框架
  - 透過twing語法，印出從Controller取得的資料
  ![](https://i.imgur.com/x32eHWM.png)

### 公佈欄列表頁的實作
- 撰寫 ***AdminController.php***
  > 檔案位置 : ***專案/module/News/src/Controller*** 內
    
    -  *indexAction()* 實作內容 : 列表資料存取-邏輯處理
    > ![](https://i.imgur.com/Pt6oD4L.png)

- 撰寫 ***index.twig***
  > 檔案位置 : ***專案/module/News/view/news/admin*** 內

  - 透過twing語法，寫入繼承的view框架
  - 在這個view內建立表單及印出從Controller取得的data資料
  > ![](https://i.imgur.com/f1i1oxF.png)
  
  - 在inline 區塊內，寫入編輯、刪除按鈕的點擊觸發事件
  > ![](https://i.imgur.com/bn6DIEI.png)

### 公佈欄編輯的實作
- 撰寫 ***NewsForm.php***
  > 檔案位置 : ***專案/module/News/src/Form*** 內
  > 為 ***edit.twig*** 內會使用的Form表單的設定皆在此
  > - 先新增以下資料夾與檔案
  > ![](https://i.imgur.com/Ylm7heO.png)
  > - 在 ***"NewsForm.php"*** 內先建立好建構式等，並建議從MySQL Workbranch 內 EER Diagram 複製 SQL出來並貼上到程式內參考
  > ![](https://i.imgur.com/TAwa8NF.png)
  > - 在建構式內建立與表單標籤對應的方法，請參考下圖方式
  > - 並在建構式外建立一個表單過濾的相關方法: ***"addInputFilter()"***
  > ※相關官方文件參考 : [Form Element](https://docs.laminas.dev/laminas-form/element/element/)
  > ※相關官方文件參考 : [Inputfilter](https://docs.laminas.dev/laminas-inputfilter/intro/)
  > ![](https://i.imgur.com/uwfDGjt.png)


- 撰寫 ***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)

