今天正在開發 v4.0
發現舊版本一個很有趣的地方,版友們會到純靠北工程師 平台上發表文章,發表文章之後會透過審核系統審核,最後發表到各大社群平台當中,但每個社群平台所能容忍的文字數量各自不同,像是 Facebook 就沒甚麼文字限制,而 Twitter 就有英文 280 字或是中文 140 字的限制,而 Plurk 則是 360 字,這個在之前發表文章的方法中就有註記這個訊息。
所以為了讓文章發表到 Facebook 的時候,文章內容可以用比較可控的方式來彙整,我寫了一個 buildContent
的方法,只需要把版友的文章內容丟進去,然後一些需要設定的參數丟進去,這個方法就會回傳我所想要的內文給我。
1 2 3 4 5 6 7 8 9 10 11 12 13 public function buildContent ($content = '' , array $options = [] ) { return '#純靠北工程師' . base_convert ($options ['id' ], 10 , 36 ) . "\n\r----------\n\r" . $content . "\n\r----------\n\r" . '🗳️ [群眾審核] ' . route ('frontend.social.cards.review' ) . "\n\r" . '👉 [GitHub Repo] https://github.com/init-engineer/init.engineer' . "\n\r" . '📢 [匿名發文] ' . route ('frontend.social.cards.create' ) . "\n\r" . '🥙 [全平台留言] ' . route ('frontend.social.cards.show' , ['id' => $options ['id' ]]); }
但是如果文章要發表到 Plurk 或者 Twitter 的時候,因為他們各自有文字上的限制,所以 buildContent
這個方法需要複製貼上到相對應的 Service 當中,稍加改變一下運作內容,需要加上內文的限制,有多餘的就要刪掉以 ...
來代替。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 public function buildContent ($content = '' , array $options = [] ) { $_content = (mb_strlen ($content , 'utf-8' ) > 100 ) ? mb_substr ($content , 0 , 100 , 'utf-8' ) . ' ...' : $content ; return $options ['image_url' ] . "\n\r" . '#純靠北工程師' . base_convert ($options ['id' ], 10 , 36 ) . "\n\r----------\n\r" . $_content . "\n\r----------\n\r" . '🗳️ [群眾審核] ' . route ('frontend.social.cards.review' ) . '?' . Str ::random (4 ) . "\n\r" . '👉 [GitHub Repo] https://github.com/init-engineer/init.engineer' . '?' . Str ::random (4 ) . "\n\r" . '📢 [匿名發文] ' . route ('frontend.social.cards.create' ) . '?' . Str ::random (4 ) . "\n\r" . '🥙 [全平台留言] ' . route ('frontend.social.cards.show' , ['id' => $options ['id' ]]); }
之前的 buildContent
方法可以完成我所希望達到的效果,但是它會存在於每個平台 Service 當中,而每個 Service 的 buildContent
皆大同小異,只有字數的功能上不太一樣,如果未來我希望安插其他內容、移除多餘的內容,那我就必須在每個 Service 都修改,這段方法耦合性太高了,因此在 v4.0
決定將它抽離出來,並以流暢介面(Fluent Interface)的方式去實踐。
延伸閱讀
1 2 3 4 5 6 7 class ContentFluent { }
再來開始思考,如果文章內容的結構會有頭(Header)、身(Body)、尾(Footer),頭(Header)的部分不外乎就是要處理 #純靠北工程師{id}
這段內容,而身(Body)的部分單純只要顯示使用者所發表的內文,但必須另外提供內容最大上限(limit)的設定,最後尾(Footer)的部分則是需要設定各種超連結,因此根據這些特性下去設計了 header
、body
、footer
這三個方法,並且去設定相對應的參數,最後回傳整個類別。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 class ContentFluent { protected int $id = 0 ; protected string $content = 'Undefined' ; protected int $limit = 0 ; protected array $footerOption = []; public function header (int $id = 0 ) { $this ->id = $id ; return $this ; } public function body (string $content , int $limit = 0 ) { $this ->content = $content ; $this ->limit = $limit ; return $this ; } public function footer (array $option = [] ) { $this ->footerOption = $option ; return $this ; } }
當內文格式設定完畢後,需要提供一個結尾獲得結果的方法,因此把彙整的邏輯寫在 get()
當中,開始把先前所設定的資料一個接一個的組合起來。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 public function get ( ): string { $response = "#" . app_name () . base_convert ($this ->id, 10 , 36 ) . "\n\r----------\n\r" ; $content = ($this ->limit != 0 && mb_strlen ($this ->content, 'utf-8' ) > $this ->limit) ? mb_substr ($this ->content, 0 , $this ->limit, 'utf-8' ) . ' ...' : $this ->content; $response = $response . $content ; if (isset ($this ->footerOption['review' ]) && $this ->footerOption['review' ]) $response = $response . "🗳️ [群眾審核] " . route ('frontend.social.cards.review' ) . "\n\r" ; if (isset ($this ->footerOption['github' ]) && $this ->footerOption['github' ]) $response = $response . "👉 [GitHub Repo] https://github.com/init-engineer/init.engineer" . "\n\r" ; if (isset ($this ->footerOption['publish' ]) && $this ->footerOption['publish' ]) $response = $response . "📢 [匿名發文] " . route ('frontend.social.cards.create' ) . "\n\r" ; if (isset ($this ->footerOption['show' ]) && $this ->footerOption['show' ]) $response = $response . "🥙 [全平台留言] " . route ('frontend.social.cards.show' , ['id' => $this ->id]) . "\n\r" ; return $response ; }
最後在發表文章到社群平台時,就只需要透過 Container
來獲得 ContentFluent
類別,並且直接 header
、body
、footer
逐一設定,並直接 get
出來,整個程式碼都變漂亮了,也解決了耦合性的問題。
1 2 3 4 5 6 7 8 9 10 11 $contentFluent = Container ::getInstance ()->make (ContentFluent ::class );$message = $contentFluent ->header ($cards ->id) ->body ($cards ->content) ->footer (array ( 'review' => true , 'github' => true , 'publish' => true , 'show' => true , )) ->get ();