2015年12月30日 星期三

2015 Summary,每年最後一篇網誌,總是一些流水帳....


心情
2015 年的心情算是中下吧,總結一句話就是燒錢的一年,忙忙碌碌,最後好像也搞得自己一場空?! 也許是短時間內看不出成果吧 反正都過去了,也差不多迎接新的開始,要認命一點。


(攝於成都 天府廣場站)

旅行
今年去了三個國家,都不敢說自己是出去開拓視野,因為真的是出去玩 XD
* 美國-舊金山
* 日本-北九州
* 中國-成都 (現在想起來遊記還沒發佈,晚點再來整理 :P)

出國玩還蠻開心的,越來越能夠獨立的做一些事情,不過三次出國還好有都朋友幫忙,不然我可不敢一個人出國 XD  2016 年我還想要再去 1-2 個國家玩玩 :P 現在最想去的是英國吧(但是要存很多很多錢...)...


戰果
2015 在公司做些什麼我就不多說了XD,我也不能說 :D 科科。
在公司學到最多的應該是測試,接觸到 travis 的感覺很新鮮,剛開始動不動就會想要去等結果 XD,但是我寫得很爛啦 XD 很不熟其實...,還是要感謝公司同事的包容跟教學相長 XD (天吶我好官腔!!!)


2015 年的閒暇時間,總共完成 14 個專案,其中 1 個是跟新加坡人合作 UI 設計,3-4 個主要以前端切版與 RWD 為主,剩下的則為 Full Stack 狀態,開發主要還是以 PHP 為主,有些專案是我 standalone,有些是跟別人一起,coding 的對象都是比我強的人,覺得小有成就感~,只有一個案子很可惜,我跟一個很棒的 team 合作,但是成果最後 fail 了 :'(。

前端常用的整合工具,目前還是離不開 gulp 的生態,還有我也沒有追上 react,倒是 PHP 經歷 laravel 4 -> Laravel 5 的過程學到很多,對 class, interface, trait 的用法比較懂了。

說不上離開前端這個領域很遠,只是在實作上,真正應用在可以客戶所追求的地方上,我確實也無法用這些這麼潮的框架...(時間上也沒有這麼閒可以一直追新東西),客戶多半要的是穩定,可以好找到人接手的環境跟技術。當然,有一種夥伴也會要求我用新的東西,通常那種就不是普通的合作對象,而是對方自己就是 coder XD,不過這種合作以我的狀況我是不太愛接觸(既然是閒暇時間就想做一些有把握的事)。

我現在覺得在 blog 上寫的好像很簡單似的,可是想起一些過程還算是歷歷在目的,有些情況也是很有壓力... 像是第一次接觸用 Laravle 做多國語系,串接臉書 API 做 tag 朋友, 發文功能,這些看似很平常的功能,當這些事情全部落在我一個人手上時,處處都有細節要處理。默默的開始假裝自己是半個 PM,假如一個專案上線扣除臉書 api 審核的時間,以及被退回的時間大概還剩幾天可以開發, 測試之類的。偶爾也成為朋友想要發包網站出去時的半個顧問職,朋友嘛 :) 出一張嘴的工作當然隨時都能聊聊 XD (逃)


學習
除了年初的 Bing Ad,  Google Analytics 證照之外,剩下的就是拿了五門 Coursera 課程,還有在五倍紅寶石講了6次的 Basic JavaScript (雖然我也不知道講得好不好 XD)

Coursera 的 R Programming 我上了兩次,作業沒時間寫,就沒畢業,好難過 QQ

研討會的話也常跑中研院,只是多半都是跟資料科學有關,Data Science 是離我很遠的世界 (遠目),很遙遠但是可以刻意接觸他,反正很多事都不是一蹴可幾 (我說了成語了嗎?!),我也不是主要靠資料科學吃飯,只是還有興趣就多聽聽,研討會的價位都算便宜了


目標
年末年初,我過的日子多半是看一些跟軟體開發有關的書,不管是把規模做大的書,還是整合工具的介紹,測試等等的。心中是有想做的事情,只是還想保留一下,因為很多事都不確定。我想我是個怪咖吧... 也許是自己快要 26 了,有點小緊張,我喜歡默默地去做一些往目標走的事情,等做到了再來說,科科 :P

新年快樂啦

我終於看完大話重構了...


之前一直看到朋友在 FB 牆上推薦這本書,買了 2-3 個月,這週終於把他看完了,適合有 coding 經驗的人,有一定的工作經驗,書本的範例讀起來會更有感覺,而且會默默地(也沒有真的到多默默啦... 畢竟目錄也有寫 :P)大概瞭解到幾種設計模式,像是 SRP, OCP, AOP, DIP, 橋接, 策略, 命令, 裝飾者模式~

最有感觸的段落是:
* 如何解決繼承氾濫
* 減少使用 if else 的幾個方法


封面講的重構七步驟其實就是:
1. 拆分大函數 (大函數是罪惡根源 XD) (Extract Method)
2. Extract Class
3. 提高程式的復用率 (DRY, 抽方法, 抽類別, 封裝, 抽取父類別)
4. 找出可擴展點 (幾個方法: OCP, hooks, AOP)
5. 降低程式依賴度 (工廠, 依賴反轉, 橋接, 策略, 命令, 組合, 裝飾者)
6. 分層 (比方說 web 是有幾種層次, MVC 層, BUS 層, DAO層等等)
7. 領域驅動設計

老實說,第9章我自己是看得很吃力,講的那幾個模式 (橋接, 策略, 命令, 裝飾者),我有點不知道如果是 php 會怎麼實作(也許我應該去讀一下 PHP設計模式那本書)... 然後書中的範例主要都是用 java 的 Spring 框架,用了一堆 <Bean>  也是開始會有點亂掉 ><。然後 OCP 本來覺得沒有這麼複雜,看了第九章之後,慢慢 fadeOut 了~ 可能我要再過一段時間再回來看這本書吧... 等級沒這麼高,還需要時間培養一下...


最終的重點就也是那些網路上大神的常談:
1. 有時候無招勝有招,學了 Design Pattern 不一定要急著用在自己的專案上,主要還是要考量情況
2. 沒有人可以一次重構就到位,小碎步前進
3. 重構是一種習慣,重點在於你有沒有這樣的意識


看完之後,確實手癢癢,可是主要是如果有人帶你學這些,會更快,我也希望我早點遇到一個可以教我 refactor 我的程式碼的人。以重構七步驟來說,1-3 step 都曾經在工作上有前人的教導我才慢慢起步。

(我是很想學重構,也算有興趣,只是時程有壓力的話,我承認還是拋開我的羞恥心了...,客戶是我的老大)



2015年12月16日 星期三

Meteor 安裝 jQuery validation

用 meteor 指令安裝 jQuery Validation(套件網址)

指令:
meteor add themeteorchef:jquery-validation


用法:
一樣參考套件網址,主要有兩種做法,一個是把驗證的設定寫在 input 的 attribute 裡面,像是 <input type="text" name="name" class="required"> ,但是一樣要用 js 去呼叫 validation 執行($("XXXX").validate())。

另一做法是把驗證的規則寫在 validate 的 options 裡面。像是:

基本上做法一,二都會在 onRender 的地方呼叫。
記得也要把 submit 那顆按鈕的預設行為取消 (submit preventDefault 那一段),不然也許邊驗證時也早就 redirect 到 action 出去的頁面了 XD。

樣式改寫 for Bootstrap:
因為 jQuery Validation 在驗證到錯誤或是未填的 input 時,會在 input 附近塞入 error message,但是預設的樣式並不符合 bootstrap 的樣式,像是:

為了讓錯誤的樣式符合 bootstrap 的樣子,要改寫一下 jQuery Validation 的 setDefault 的一些 method,像是 highlight, unhightlight...,但是因為整個網站下,有很多頁面只要有用到 jquery validation 的地方都必須要改寫驗證,為了節省一直複製貼上這一段到每一個頁面/template 的 onRender 去,所以我把這段改寫放到 Meteor.startup 的 function 去(我在根目錄下新增一個 startup.js 來擺這段 code):

改寫後,暫時符合預期:


其實在網路上有找到兩個解法,這個是我用起來比較順的,只是寫出來分享一下而已,也不知道好不好~自己斟酌摟 :P。

參考:
http://jsfiddle.net/m2o6c2vj/3/
http://stackoverflow.com/questions/18754020/bootstrap-3-with-jquery-validation-plugin

2015年12月15日 星期二

讓 Meteor 在換頁時頁面定位到最上方

最近在用 meteor 搭配 iron-router 做一個 web 後台的雛形出來,但因為 meteor 的設計還蠻特別的,所以有些行為跟一般做換頁的網頁效果不太一樣,主要是比較像是 Single Page Application,你在換頁的時候感受不到瀏覽器有在重新 loading 的感覺,所以換頁時,你的 viewport 可能會停留在上一頁的看到的地方,為了不讓 user 感到困擾(<- 視頁面情況..),在 github issue 上面找到一個解法,要在 iron-router 的 filter 加上一個方法,這個方法用來讓頁面捲到最上方,然後把這個方法掛在 Router 的 onAfterAction。


(* 我的 meteor 版本是 Meteor 1.2.1)

那一串 github issue 有很多討論,但是我是用這個方法
有成功拉,好險好險 :)

2015年12月12日 星期六

2015 年末的小認真之 Coursera 上上課

人生啊...


課程

(1) Courser 的延世大學 - Big Data, Cloud Computing, & CDN Emerging Technologies


12 月最先開跑的學習是關於 IoT 的一些基本觀念,首先上的課程是 Coursera 延世大學的 Big Data, Cloud Computing, & CDN Emerging Technologies,這真是一門基礎到不能再基礎,而且濃縮所有基本觀念的課程,w1 真的就是在講一些 big data,w2 是 Hadoop 的基本觀念,是有稍微提到 YARN, 還有一點點 RDBMS,w3 就是 CDN 的觀念跟這個產業的幾個公司,大概知道一下那個市場範圍在哪裡,但是光看課程是感受不出技術上的難度跟落實的難度有多複雜啦,anyway 我只是有時間的時候當作影集在看,題目也蠻簡單的,有認真上一定 pass. 雖然我最後只拿80分結業,汗顏 XD

哦對了老師好像是韓國人?!,雖然我覺的老師的英文腔調很特別,不過聽到 w2 就習慣了啦 :D
老實說這種基礎觀念的課程不拿專項課程真的很可惜,不過就看我時間,其實我是很想整個專項都拿下來。哎,循序漸進嘛... 資質卑劣.. 太難的我也不懂啊

(2) Coursera 杜克大學 Java Programming: Solving Problems with Software

Duke 大學的 Java 課程很有條理,我覺得蠻推薦的,而且這門課超級不太 web,但很有新鮮感。Duke 設計這門課程還寫了一個叫做 BlueJ 的工具,上課講 code 都是用這個工具,我是覺得蠻適合 Java 新手,是還蠻厲害的!

week1 教你用 java 去選取圖片,然後針對圖片做簡單的影像處理,像是灰階, 或是 RGB 中間兩個色系互換之類的,聽起來很難但真的... 不難 QQ w2 開始就有點複雜了..。

w2 課程是要教你在 DNA 的 String 找出基因,但其實就是在教 String 的操作啦! 但我覺得上起來相對蠻悶的 XD 有點難,w2 後面段是要教你爬網頁的 html 的內容,像是找出幾個 link,哪些 link 是 https 結尾等等。

w3 是 CSV 檔案的處理,上這堂課才知道 CSV 是一個 standard XD (IETF RFC 4180: comma separated values),然後用 apache CSVParser 這個 lib 去練習寫 CSV Parser。

anyway... 我還在修,但我覺得我不會 pass



(3) Coursera 約翰霍普金斯大學 A Crash Course in Data Science

Executive Data Science 數據科學管理專項課程是最近才看到的課程,比較輕鬆引導式的方式,我還差三門要上,現在就只有上 Cash Course in Data Science 跟如何建立 Data Science Team,但這門課很基礎,所以,想知道什麼就自己去看看好了,課程很短。


(4) Coursera 約翰霍普金斯大學 Building a Data Science Team

如何建立資料科學團隊,這是接續上一堂的課程,看完之後覺得... 哎呀 台灣有幾家注重資料科學團隊的公司?! 有幾家願意投資時間做資料科學的?! 因為做資料科學是很有挫折的事情。也許花個一年半載的,才有機會發現有 value 的東西,可是願意讓這種團隊在公司待個一年半載才看到成果的公司,少之又少的 feel~ 錢跟時間都要燒得起QQ。我是覺得跟公司文化有很大的關係(不確定? 只是覺得...)


(5) Coursera 倫敦大學 & Goldsmiths, University of London  的 Introduction to Meteor.js Development



在過去一年曾經整年都在用 node.js 寫 web application,只不過用的是超輕量的 koa.js,在過去用 node.js 的期間常耳聞 Meteor 這個 framework,但就是台灣用的人太少了 (->也許是我朋友太少!?)  剛好趁這個機會探探 meteor 的用法。

上這門課只是開開眼界,多看看不同 framework 的做法,至於好不好很難評論,一個 framework 就是一種生態, by case 你會有你想選擇的 best one, 也沒有好不好的問題。

結論就是 Meteor 跟 MongoDB 是蠻搭的,只是我手邊沒有案子可以玩這種架構。上完的心情就是我很愉快但是 see you next time.  真的想不出拿時候用的到,maybe 做個網站或是 app 的 prototype 會有機會。


目前生活總結
本來正在寫 PHP,後來劈腿 Java,還跟 node.js 繼續曖昧,現在處在一個很亂的關係當中

很窮但很快樂.  希望心想事成!

現在還有幾堂課正在上,有什麼心得就再說啦! 考驗我的意志力

2015年12月3日 星期四

Mac 安裝 Eclipse

最近開始在看一些 Java 的書,比較尷尬的是現在最新的 Java 是 8,但是很多書都還是 Java 7。

要寫 Java 就要先安裝 JDK (Java Development Kit),也不是第一次學程式了,這些基本的 SOP 上網 google 一下 XD

IDE(編輯器)的話,你可以選擇裝 Eclipse 或是 NetBeans IDE, 或是 IntelliJ IDEA。

因為還是 Java 新手,圖書館的書隨手一拿,我看書的是歐萊禮的 Learning Java Foutth Edition (<- 但我並不覺得這是本很好的入門書 XD 需要有寫過一點程式的經驗再看比較適合),書上的範例用 Eclipse。 在 mac 上推薦裝 Eclipse IDE for Eclipse Committers X.X.X (我是裝 4.5.1)但是檔案非常大(約 243 MB),如果你跟我一樣在星巴克而且手機沒有吃到飽請你先別衝動。

另外安裝 Eclipse 也要先安裝 Java Runtime Environment (JRE)。
基本上,缺什麼就裝什麼,警告訊息會帶你到正確的路。

2015年11月20日 星期五

Mac 安裝 JDK 的路徑

剛剛在跑 android studio 的時候
那個 JDK 的位子一直說我只有 jdk 1.6.0
但我裝了 jdk 1.7.0, 1.8.0  都沒有看到
原來是目錄錯了...
因為它裝在  /Library/Java/JavaVirtualMachines 目錄下
而 Mac 本身就有裝 Java,天生安裝好的 Java 路徑是在  /System/Library/Java/JavaVirtualMachines

所以,指定目錄的時候,不要跑錯地方,不是沒裝好 JDK...

2015年11月19日 星期四

如何比較無雷地安裝 PHP7

前幾天同事 R 內部分享了如何正確地安裝 PHP7
據他本人分享,踩騙千千萬萬個雷,歸納出來的重點是:
『看 Laravel 的老爸怎麼裝,就怎麼裝!』

別說編編沒有讓大家看到這篇的重點,
https://github.com/laravel/settler/blob/php-7/scripts/provision.sh
這是實用的 script,
如果你是用 aws 起 ec2,在 user-data 的地方只要貼上這個 script,
如果你不想整包都靠這隻 script,那就看 script 把你不要的地方捨去掉,
主要是這包 script 把一些東西都裝好了,除了 php7 之外
composer, hhvm, nginx 什麼的都會裝。


2015年11月18日 星期三

台胞證申請

最近辦了台胞證
去旅行社跟櫃台說 你要辦台胞證
會給你一份申請表格,帶著你的

1. 照片
2. 護照(有照片的那一頁)影本
3. 身分證正反面影版本

還有費用,因為我是普通速度案件,所以 1300 台幣(急件會比較貴),不包含申請當天,五天後可以拿到。

如果你想幫別人代辦,也ok,但建議先去旅行社拿那張申請表,因為表格下方需要申請人簽名。

表格比較有趣的是,職業不能亂填,有一張表可以對照,然後填寫表格的職業文字。


大概是這樣,沒什麼特別的,接下來就是機票,跟換好人民幣,就可以出國啦!
如果你跟我一樣都是 Android 的手機,記得出國前把必裝 app 裝好,像是 VPN 工具,滴滴打車,大眾點評,QQ,WeChat,百度地圖等等。

2015年11月17日 星期二

translate3d 為什麼會讓子層的 css position fixed 失效... ?!

在處理一個 header 位子要固定的問題時,發現怎麼樣也都無法 fixed

超級詭異....

找超久才發現原來是因為我在 body 加上了這個 css 屬性: 

-webkit-transform:translate3d(0, 0, 0);
-moz-transform:translate3d(0, 0, 0);

原因不明,我也想知道為什麼,如果有人知道,請告訴我謝謝 :)

這是造成無法 fixed 的 demo:
如果把 body 的 transform:translate3d 拿掉,就正常了..... 

2015年10月14日 星期三

PHP 進行斷字還是用 mb_ 開頭的好?! (substr v.s mb_substr)

我們常在什麼 XX 列表上,有時候因為一行文字過長,所以會有想把文字做截斷的動作,比方說 『i love you so much, do you know』,假設這段文字剛好擺進 div 時就是會過長,所以我想要把他截斷成 『i love you so much, do...』,最後還故意加了 ... 來表示。

假設這個問題只會發生在單行文字,那我會建議你用 css  的 ellipsis 解決掉,因為單行的段字做 ... 結尾用 css 蠻快的,但是發生在兩行或三行是就不能用 css 了。

這裏有一段很簡陋的程式碼,用意是每一筆 title 我都會判斷它的長度是否超過我認為的最常的可能性 (目前看起來是我希望他不要超過 39 個字),過長我就會用 substr 把它截斷,從第 0 個位子截到 39,最後補上 ... 字串:


不過很可惜這樣的做法有問題,我假設我存在資料庫的字串都是正確的字符編碼,可是經過這個 substr 截出來的字串,卻讓我得 � 奇怪的詭異符號,為什麼?!

經 google 發現原來 substr 算的是 bytes 而不是 characters,取而代之的是,如果你使用 mb_ 開頭的 function,可以額外處理 multi-byte encodings 的部分。

後來我用 mb_substr 將以上的程式碼改寫了一下: (要注意 function 的參數跟 substr 數量不太一樣)



每次在追這種怪問題都覺得心疲,但是得到解答後就覺得好多了

這個需求讓我想到以前工作的一些經驗,因為英文字跟中文字算出來的大概要擷取的數量是不一樣的,所以... 挺麻煩的。有時候 不要為了一些沒必要的堅持而堅持。

如果還有什麼不瞭解的地方可以 google substr vs mb_substr。

只是我還是不知道,到底在什麼情況下,我們會只用 substr ?


2015年10月13日 星期二

Rails Girls Weekly - JavaScript Basic For 6 Weeks(5/6)


剛剛上完了第五週的課程 jQuery 基礎,其實是真的非常基礎 :P 花了一個多小時帶一下。另外也有提到 Framework 跟 library 是不一樣的概念,如果想學 jQuery,把 css selector 弄懂很重要,如果你是初學者,可以學習以下兩個網站為開端:


http://flukeout.github.io/
https://www.codecademy.com/en/tracks/jquery

2015年10月12日 星期一

[隨筆] 用 css mask-image 做遮罩

晚上剛好幫我朋友看一個 colorbox 的問題,起初我以為只是一個改改 css  border-radius 就好的問題,沒想到弄到最後竟然去找 mask-image 的方法。

情況是他希望在 colorbox 打開時,四邊都維持某種程度的 border-radius,但是在 colorbox 的 iframe 裡面,當你 scroll 時,border-radius 就失效了,其實不是失效,而是裡面的 div 的背景色本來就存在於那個區域,所以 content 是滿的沒有錯

廢話不多說,我只能講最後我用了這個方法,他使用了 mask-image 的方式去做遮罩的概念,在 colorbox 那一個 iframe 做這層,就可以一直 mask 四邊都有 border-radius 的效果:  How to make CSS3 rounded corners hide overflow in Chrome/Opera




改完之後不管裡面怎麼捲,都能維持外框有 border-radius 的情況:


太久沒有好好研究 css,已經退化到這種程度也真是一種悲哀。
因為 colorbox 一直都是網頁製作 popup/lightbox 當紅炸子雞的套件,所以我還是記一下,以防以後有需要用到又忘了。

2015年10月9日 星期五

Rails Girls Weekly - JavaScript Basic For 6 Weeks(4/6)

昨天本來要發文,但是想說早上還要去參加 phpconf 2015 所以就早早睡了 :P

week4 講了基礎的 array, object 怎麼定義,還有 JSON,雖然講到 JSON 有點難了..sorry。
因為加了一小時講一點怎麼 commit 到 github,所以昨天有兩個 slide,只是最後 live demo 的時候沒有成功,不知道網路還是 github 怎麼了,有點可惜就是.. 下次我還是不要嘗試做這種 live demo 的事好了 QQ

老實說簡報都很基本,但是還是要看個人的接受程度,也有有些人會覺得很難,只是有些事情,就算當下的聽眾不能接受,我還是必須說一下,主要是因為這些都是"定義",該描述出來的事情還是得說一下...。

2015年10月7日 星期三

git 反悔 commit,想要 rollback 恢復回到上一次的 commit

最近在工作上偶爾需要這個功能...,就是一直去 merge 別人的 branch,結果上一次 merge 的結果是有問題的,就會想要還原之前的版本,模擬的情境像這樣 (圖中的 SHA1 都是假造):

假設我有一個 branch 叫 winwu,這是我每次 commit 倒數幾個的歷程:



由於最後一次 commit (紅色那顆 ew3354) 其實是有問題的,所以我希望退回到 2Tefw88 那個 commit:



指令是:
git reset --hard 2Tefw88
git push origin winwu --force

簡化的表達方式是:
1. 首先 reset -hard 先“強制”回到某次 commit
git reset --hard 要 Rollback 的 commit SHA1
(有 --hard 也有 --soft,用法我沒有提到,可以自己去查查看 :P)

2. 接著重新 push 到你想要 push 的 branch,記住一定要有 force,否則 commit 不上去哦...
git push origin BRANCH 名稱 --force


參考文章:
Git 版本控制:利用 git reset 恢復檔案、暫存狀態、commit 訊息 - appleboy
http://stackoverflow.com/questions/927358/how-do-you-undo-the-last-commit
http://git-scm.com/docs/git-reset


2015年10月6日 星期二

2015 南投集集亂走亂逛兩天一夜


這個週末因為朋友要去南投參加衝小鎮的活動,所以身為他的朋友跟朋友們也都一起跟去了 (講義氣 XD),不過沒有特別安排什麼行程,就只是當做出門踏青,隨意走走而已。

交通
去程:  (高鐵)臺北->台中新烏日(700多),然後從新烏日搭電車到二水,再直接換月台轉搭到集集的區間車。時間要對準,因為二水到集集的區間車沒有很多,如果錯過一班,可能下一班要 1-2 小時才有。

回程: 區間車從集集到二水,再從二水搭自強回台北 (487元)。

Rails Girls Weekly - JavaScript Basic For 6 Weeks(3/6)

PPT


本來今天的課程是上週的,只是剛好遇到颱風,所以延到今天:P
week3 講的是基本的 event 跟 function
其實真的要細講,都不是一兩小時能帶過的,如果大家覺得這份簡報,有什麼很基礎而我沒有提到的部分,也歡迎讓我知道,這樣有朝一日還要分享基礎 javascript 才有機會改進呀 !

謝謝來上課的朋友們,如果有什麼做不好的地方,直接反應吧! :)

2015年9月30日 星期三

Laravel 在 Eloquent alias table 名稱

在 Laravel 撈資料的時候發現有時候 Eloquent 很不好組,尤其是有 sub query 的時候....,後來用了 DB 的方式去做 Query:
$query = DB::table('xxx_xxxx AS a')
     ->where(
         'a.GG',   '=',
         DB::raw(
            '(select max(GG) from xxx_xxxx as b where xxx_xxxx.`no` = b.no)'
         )
)

但我後來發現原來 alisa 在 Eloquent 有方法耶...
在 Eloquent 使用 Alias,只需要使用 from 的這 static method,比方說上面那一句可以改成下面這一句,後面的 where 幾乎是沿用就可以了。

$query = XXXXXXX::from('xxx_xxxx as a')
$query-> where(
'xxx_xxxx.GG,  '=',
DB::raw(
'(select max(GG) from xxx_xxxx as b where xxx_xxxx.`no` = b.no)'
)
);
堅持要用 Eloquent 的原因是,之前改了一些 getter/setter (accessors and mutators),如果今天用 DB:: 的方式去撈資料,我改寫的 getter 好像就沒有作用了,哭...,還好後來還是有找到方法,硬是全用 Eloquent 的方法取資料。




2015年9月23日 星期三

關於買樣板來製作網頁這一件事情

穎(@look_me08)張貼的相片 張貼

(因為不放圖顯得很空洞,所以放一張今天晚上在左道咖啡的照片)

今天買了一套 Admin 介面的樣板,我想起這件事情,還滿值得研究研究談一下想法。事實上我很常買樣板,甚至有些我根本也沒有用到,不過買回去第一件事情,想想別人為什麼可以做樣板做到可以拿來賣錢,一定有它方便於我的地方。

首先,完整性不用講,常常我們腦袋裡想的天馬行空,後台想要多牛B就多牛B,但就是不想動!? 對吧,於是幻想就停留在那一刻,然後刻出來的東西照樣平庸。

接下來是樣板有時候是『學習的樣本』,你可以買到用 Angular 製作的樣板,bootstrap 一樣,很多很多,你可以透過套過樣板知道別人怎麼把這一堆前端的 library, plugins 『兜』在一起,就算手法不是很高明,但也是一種解決方案,千萬不要覺得這些事情很簡單... 前端是很苦工的...。

可以學但不要照單全收,有些樣板不一定是很有組織的程式碼,這樣也是挺合理的... 因為畢竟他可能只是在 demo 某一件事情,通常你買來可能還需要再整理過。

再來是學習使用現有的樣板套用在自己的系統上,不論你的 template engine 是什麼,趁機組織一下頁面可以共用的地方,分出哪些是東西是 layout, partial, widget, 或是 bla~bla~bla~,有助於一點點習慣程式喜歡『re use』的概念。


當然也有人會認為,買樣板沒有樂趣,很有可能撞板或是什麼的... ,我個人是覺得只限於後台或是內部系統會買。前台的話,我還是喜歡有設計過的網頁 :P

只是想起,有一次在做手機版網站,當時還菜,一直不懂為什麼手機上看我的網站,那顆 menu 的按鈕按下去之後,感應很緩慢,不知道有 fastclick 可以幫我解決手機上 click delay 的問題,這點,從樣板學來,所以我知道了有這個工具。

第二個經驗是,樣板使用的 plugin 有時候會讓我驚訝,『原來有這種工具!』的心情。

前端是一個做久了有時候會很沉悶的工作,但偶爾發現一些驚喜,內心還是會很澎湃的,也許有這樣的心情的時候,才發現自己已經是個有點懶散的老鳥了...,因為懶,所以我寧可刷個幾百塊錢買樣板,企圖得到一個系統看起來很完整,能 work,眼睛順眼的結果。


2015年9月22日 星期二

Rails Girls Weekly - JavaScript Basic For 6 Weeks(2/6)

(圖源: Railsgirls Taiwan 粉絲頁)

這週是 week2,講的內容是關於 JavaScript 的 dialogs box,還有一些條件判斷。

上課是還蠻輕鬆愉快的啦,希望大家都堅持的下去,可以一路上到 week6 :)

其實可以的話,看 readme 比較清楚。
github repo: https://github.com/winwu/javascript-basic-toturial/blob/master/week2/README.md


PPT:


『在 PHP 上學會自動化測試與實戰 TDD』 ... 下課後


前言
我自己剛開始在使用 phpunit 遇到的一些問題: (嚴格來說也不能說奇怪... 要說自己涉世未深..)
1. 效能問題 (越跑越慢, 甚至慢的奇怪).
2. Database 沒有設定好,設定錯誤導致應該要以 SQLite 而不小心跑成 MySQL.
3. 類別的 Mock 不會寫.
4. tearDown 的地方有時候會忘記.
5. 測試碼太多支時,會有點不知道怎麼組織
6. 會丟 Exception 的 function 不知道怎麼測,又不希望被標成 risky tests (phpunit 如果發現你的  測試 function 根本沒有 assert 時會出現的訊息)
7. 知道的 assert 太少 (雖然這完全是沒唸書的關係...)


上週末,去上了兩天小鐵(大澤木小鐵)的 TDD 課程,更了解 TDD 的連續兩天 workshop,算是非常有收獲,尤其七,八月以來,工作上的團隊開發也漸漸開始使用 TDD 開發,雖然很不熟練,用法用的亂七八糟,但是也是因為有過這些錯的經驗的接觸之後,來上課才更能瞭解什麼是 better way,我還蠻喜歡這種感覺的,就是我不喜歡從0開始,然後一直讓別人來教我什麼是好的, 什麼是對的,這樣的感受太不夠深刻了 :P 不犯錯的學習只會讓我覺得這件事情好像不難?! 然後挑戰性就失去了...


第一天講單元測試, unit test 算是很小的單元,一次只做一件事情的測法,這個算是剛學習測試最好上手 and 理解的。再來一些原則,像是 3A ... 還有教到一些重構,因為寫測試的時候,難免會邊重構, 邊寫測試,所以學測試,跟重構也有一點關係。(我也想起自從開始學 TDD 之後,也會開始對重構很有興趣,這真的是不知道為什麼 XD) 因為這堂課的關係,我才發現 phpstorm 好棒啊! 這些 refactor 的功能 sublime 都沒有.. 雖然有些殘念,不過接下來可以在專案重構時,也趁機學學使用 phpstorm。

(圖: 主辦單位準備的點心,這紅茶綠茶讓人想到測試就是紅燈, 綠燈不斷循環阿... 但記得最後 commit 上去要綠燈就是了~)

另外 phpunit 產出 coverage 報表非常的不錯,看到程式碼開始有一點覆蓋率之後,感覺就像是有在上班啊 (誤)

第二天著重在 BDD,只能說 BDD 非常有趣,大概是因為感覺很像照著 spec 來寫測試,那些腳本寫起來,雖然很抽象...,但是我竟然是在用程式語言寫一個 spec 的感覺,很神奇+詭異,測試工具真的是什麼怪功能都有 @@ ~ 只是剛開始寫,覺得不太順暢,還需要多練習就是了...尤其 Example 用 Laravel 來講解,又更貼近於我的日常了 :P ,心得是: 相較於 TDD,我覺得團隊要導入 BDD 比 TDD 還難...,只是『感覺』,說不上很特別的理由,大概是因為 spec 本身就很難有(存在),就算有也會變動,如果今天的需求是改 spec,那麼 BDD 要改,程式改了,TDD 也要改,一個測流程,一個測功能跟程式,超 high 的 XD 感覺 commit 會很多~

在專案上的導入測試這件事情來說,我反而覺得是誰先來開始帶起這個風氣比較重要。

回家 TODO :
* 學習使用 mockery 去 Mock 物件
* behat (BDD)
* 等 91 哥開下一梯 TDD 的課程 :)

為什麼要上 TDD 實戰,跟上面的前言7點有很大的關係,因為有些情況不知道自己做得對不對,有些內心還沒有解法,所以想要更了解多一點,這樣比較扎實 :D 這兩天真的很有回饋感 XD 感謝主辦單位,也謝謝小鐵 ~

2015年9月15日 星期二

Rails Girls Weekly - JavaScript Basic For 6 Weeks(1/6)

今天去五倍紅寶石講一場 JavaScript 基礎,因為這個課程分六週上,所以今天只是第一週,投影片在此。只希望來的人都有收穫,不要充滿挫折。。。 下班還願意學習的人真的不容易 :) 辛苦了!  

下週二一樣有 week2,到時候再分享新的文章。


Coursera 機器學習基石 第二講:Learning to Answer Yes/No [二元分類] 筆記 (很亂,不要看 ><)

這兩天看的是第二講

我可能還要再找週末時間整理吧(預計中秋連假...)
(目前在尋找好編輯數學公式的工具...)。

奧.. 我非常累,先睡
事情已經多到我覺得是我的極限了。


2015年9月13日 星期日

Coursera 機器學習基石 第一講: The Learning Problem 筆記

請大家忽略這篇吧...
這是記錄給我自己看的,筆記很亂,只有我自己看得懂 :P
林軒田老師的課真的很不錯,就以介紹 hypothesis 那一段來說,比 Ng 的課好理解些,或許語言真的有差吧...,雖然 Ng 的課有翻譯,可是還是有些吃力啊...

week1 講 Learning Problem,光是把影片看完,消化一下,筆記一下,大約 2-3hr 吧...
說實在還真的沒什麼把握有能力 pass 這堂課耶,程度落差大...
然後我真的睏了,沒什麼力氣整理筆記,這也是順手拿起來的紙張寫一寫...
(字醜得比國小生還醜..)


2015年9月10日 星期四

『機器學習駭客秘笈』 讀書心得 (上)


書目: 機器學習駭客秘笈
Machine Learning for Hackers - Case Studies and Algorithms to Get You Started
作者: Drew Conway, John Myles White
譯者:林威仰
出版社:歐萊禮

我一直在猶豫我到底要不要寫這篇心得,因為我到底能寫出什麼有幫助的事情我也不知道?!不過看看就好... 希望沒有浪費讀者太多時間。

關於你要看這本書的話,有幾個建議:
*這本書的範例是用 R 語言來解說,所以,比較優良的情況是,你有學過基本的 R 應該會更上手,不過也不用太擔心,第一章節會介紹 R 的安裝跟一些基本概念。
*這本書介紹了幾個常見的 Machine Learning 的方法,像是分類, 回歸, 資料分群, 最佳化。


## 前言
* 『機器學習是什麼? 抽象來說,是一系列的工具與方法,協助我們從各種記錄或資料中,萃取出其模式規則甚至是隱含其中的深層資訊。』- 第一頁。
* 這本書雖然用了『駭客』兩字,但不是我們心中所認為的那種駭客,而是指喜歡學習新技術,並且用來解決問題的人
* 機器學習涉及到非常多領域,基礎理論是數學跟統計學 (當然還有其他的啦 XD)。
* 機器學習包含許多的理論,初學者如果想要看這本書,最好可以對一些基礎的理論有所涉略。
* 『動手實做才是機器學習的圭臬』 - p.1 前言
* 機器學習有兩種方式,一個是『監督式學習』,另一個是『非監督式學習』。書中的第三章, 第四章,都是監督式學習。


## 第一章 使用 R 語言
*『統計學探討如何從解讀資料中的資訊』 - p.1
*『機器學習則是要將資料轉換為有意義的事務』- p.1
* 機器學習處理的問題不外乎兩個型態,分類問題跟回歸問題。
* R 的缺點是無法處理極大量的資料,如果你只是為了驗證幾個簡單的概念,使用 R 蠻適合的,但是目標如果是建立企業級的資料分析系統,R 就不會是最好選擇,像是 google 或是 facebook 都用 R  來做實驗性的機器學習演算法,但是真的要實戰,是會把演算法移到像 C 語言來實做之類的。


## 第二章 資料探索
(我個人覺得整理資料最難..)
這章對我來說其實在講數學比較多,會介紹平均數, 中位數, 眾數, 分位數, 標準差, 變異數。看了很頭痛的東西 XD 好想哭,好吃力...


## 第三章 本文分類: 垃圾郵件判斷
* 二分法,也就是分類問題(classification) 是機器學習常見的方法,這本書舉例了垃圾郵件判斷,分類法最重要的一個點就是特徵擷取,比方說,你拿什麼特點來認定某封信件是否為垃圾郵件? 。在這本書會介紹如何用內文的內容,去做分類,比方說某些文字出現的機率過高,有可能是就是垃圾信件之類的。

* 本文分類演算法又稱為 『單純貝氏分類器 (Naive Bayes Classifier)』,在書中的範例,將每封信的文字分成兩類的文字,一類是可能出現在垃圾郵件的單字,另一類則否,然後算出一個大概的機率,這還會談到先驗機率 (機率為多少就可以判斷是垃圾郵件) 等等。

* 章節會有實作的 code 可以看,有實做一個貝氏垃圾分類器,另外還用到了 R 的 tm 套件,tm 套件就是 text mining,用來做本文探勘的工具,還會用到 ggplot2 畫一些圖,感受一下分類的結果,恩.. 如果你覺得這章很 hard code... 那後面的章節更 hard code (哭),但蠻有趣的,如果你跟我一樣不懂實做,那就把方法看一看。

這章的範例雖然有趣,但一般的分類問題絕對不是用一個簡單的條件就可以將條件一分為二,所以接下來來到了第四章。

## 第四章 項目排序: 優先收件匣
* 這個章節其實是延續第三章,如果我們今天把一堆郵件做分類,一類是正常的,一類是可能為垃圾郵件的,再來,我們希望針對垃圾郵件的可能性做排序...

* 為一組資料做排序,也是機器學習常見的工作,最有名的例子: 推薦系統。

* 如果你還沒看過這本書,可以先思考看看: 你打算用什麼來排序哪些信件是重要的?

* 小提示: 在解決一些機器學習的問題時,視覺化資料永遠是一個了解資料的一個不錯的方法,幫助你瞭解特徵之間的關聯性。 - 參考 p.107


第五章開始我留到下回再寫,有點累,內容有點多,後面開始講看不懂的線性回歸。


結論
* R 的話,可以去上 coursera 的課,或是 datacamp,只看第一章就想要把 R 弄熟,不可能 XD。
* 這本沒有我想像中的.. 基礎 XD 可能我不是這個領域的人吧.. 感覺看這本書在平行世界,但是學到很多方法 :)。



PS: 這本書已經賣出去了

2015年9月5日 星期六

2015 台灣資料科學愛好者年會 - 系列活動 『 資料科學團隊培訓及導入經驗分享會』 活動筆記


我參加的是 2015/9/5 這一場『資料科學團隊培訓及導入經驗分享會』,以下是一些很簡單,隨手紀錄的筆記,比較片段,自行斟酌要不要看瞜... 講者說會後會分享 PPT,如果我有看到網址,我會補上 :)

有錯字請見諒 XD 打字很累的...

# 資料科學簡介 (0900:1030)
* 資料分析很像在掏金,你知道裡面應該有很有價值的金,但他稀少,一定要有對的工具把它找出來。
* 這是現在大家做大數據的困難:『有很多資料,但只拿出一點點東西』。
* 所以推廣資料科學,透過會議,研討會,讓大家知道我們有很多工具。
* 訓練資料科學家非常困難,講者覺得最重要的是溝通能力。這種人物很難找,你有聽過,但你很難遇過。

## 資料科學包含:


資料科學不是單一技術,是這些科學的集合。
  * 數學統計
  * 模式識別(雜亂的東西找出 pattern)
  * Data Mining
  * Machine Learning(讓電腦自動發展演算法)
  * 人工智慧
  * 類神經網路(幾十年前的學科,最近又開始紅了)
  * 資料視覺化
  * Big Data Modeling
  * Big Data Solution Engineering
    當你平常處理資料的方法已經不適合了,當你需要新的方法來處理新的資料,我們就需要新的技術。
  * EDA

### HIPPO
HIPPO-driven -> Data-driven
老闆說什麼就做什麼(那這家公司是 HIPPO-driven) 而不是 Data-driven。

## Data Science
大數據可以是形容詞 動詞 名詞... Example: 你這資料有大數據了嗎 XD

### Big Data
  * with height volume, velocity, or variety
  * 政府喜歡用『巨量資料』
  * 量是多大才叫做巨量? 每人定義不一點
  * 有大師認為,傳統的統計是經過抽樣,有經過抽樣的都不叫大數據
  * 資料一直進來
    * 像是電商
  * 反應速度很快
  * 多樣性,當你的資料跟以前的不太一樣,開始整合產生新的價值。
  * 我們不一定要一直去強調大數據這件事情
  * big data 太容易被誤用了

### Unknown Problem 
  * 傳統的 BI (Business Intelligence) 你知道問題,也知道答案,但是精確值不曉得。
  * Data Discovery 企業根本不知道這個問題(ex: 在哪個跨國公司有潛力?)
  * 探索式的開發,結合其他的資料,找出企業的問題,或是開發新的客戶

### Data Collection and unification
  * 因為科技的進度可以搜集到以前搜集不到的資料 (ex: 手機,手機上面有很多感應,透過手機的水平垂直,震動, 加速研究台北市公車哪一條路開的比較平穩)
  * 台北市有三千支 camera, 車上的行車記錄器, 微軟的年齡偵測。如果資料夠大,知道你是誰,你的情緒。
  * Deep Learning。
  * Google Map 過去是有大概去推估門牌號碼,但是用 Deep Learning 可以做得很準,用影像辨識處理,這是前幾年還做不到的事情,但是現在做到。

### Data Product building
  * 因為電腦處理的速度變快,所以我們很容易打造 data product。
  * 他有很多種含義,現在比較常講的是 input 的資訊,output 會直接做判斷,不用經過人為。
  * 推薦系統是典型的 realtime data product,案例像是電商,比如說 Amazon 做了 20 年了。

### Business Context (i.g.,goal => revenue)
  (--沒記錄到什麼--)


## Data Science is More Than..
* 分析工具 (R, Python)
* Infrastructure(Hadoop, NoSQL)
* Big Data(small data also do) small data 也可以小兵立大功
* Data Visualization
* Statistics/Machine Learning


## 案例
1. 計算社會學
  * 當電腦科學家遇上社會學
  * 社會學很難?! 因為它牽涉到人,不能重複,看不到因跟果。
  * 我們都需要資料來佐證,可是跟人有關的資料很難取得。
  * 涉及隱私的資料都很難取得。
  * 常用的方法: `analytics of web-scale observational data`, `virtual lab-style experiments`, `computational modeling`.
    * virtual lab-style experiments: facebook  在 internet 上做實驗,像是投票,如果是針對某個黨派做操作,是有可能造成選舉結果的。
    * Google/Facebook 可以操作決定讓你看到的內容ㄡ
    * 『排行版』是有效的。排名在前面會增加下載量,或是購買量(有可能造成買榜行為)。排行榜會不會改變你對某個東西的印象?
 
---


# 資料科學家的養成
* 技術背景

## 資料科學家
  * 統計, 機器學習, Domain specific data mining techniques, Data Visualization

## 資料工程師
* 資料錯了你好歹要看得出來呀

## 資料科學家的特質
* hacking..
* 溝通能力跟人際技巧比較重要
* 兩到三個專業知識
* 懂得企業如何操作, 如何賺錢

## 資料素養 + 創意人的訓練
* 你會再遇到問題的時候,不做假設 不偏見
* 有經驗知道這個問題該怎麼搜集資料,及分析

## 幾個建議
* 獨處跟熱情

## 在建立資料科學團隊,找不到熟手怎麼辦?
* 這種人不會在市場上流動
* 幾本上你在台灣找不到這種人
* 三項領域出發: 資訊, 數學統計, 解決問題能力
* 個人特質要具有: 細心富創意,溝通能力

## 最小團隊組成
* 講者認為理想最初始團隊: PM, 資料科學家, 資料工程師*2, ,資料視覺化工程師。
* 兩個不嫌少,先求有再求好

##『大』數據處理平台?
* 大部份的公司是在處理資料缺乏結構的問題,而不是資料過大的問題。
* 『大』不是重要的特質
* 30% 的大數據的問題在於『必須分析來自於多個來源的資料』
* 隨機抽樣是我們的好朋友

## 資料倉儲團隊 vs 資料科學團隊
* 倉儲團隊管理整個團隊的資料,但多數事情是事先被決定的。(問題會變,但資料差不多就是那樣)
* 資料科學: 資料倉儲團隊的『客戶』
*  企業領導階層指出方向之後,資料科學團隊深入資料之後,定義問題

## 釋放資料科學家
* 資料科學家不應該做報表撰寫 (解放他們吧..)

## 培養對資料好奇的文化
* 資料團隊要懂得 re-phrase 問題
* 資料團隊負責重新定義問題,以及找到答案

## 混出資料科學家
一定要有商業敏感性,你找個統計學家是沒有用的。數據部要跟業務部的人經常在一起,不只是一同開會,更要一起吃飯喝茶.

## 資料成為企業資產
企業資產而非部門資產。
制度一: 程式/資料透明化/共有
制度二: 所以資料由單一團隊組成
制度三: 資料團隊成戰略編組, 高層全力支援 (ex: 阿里巴巴~ 資料策略委員會)

國內狀況目前: 以上皆非。 XD (覺得爽)

## 資料團隊目標要明確
『你們測量過的東西,是無法管理的』- W.Edwards Deming
* 績效量化,通常不是無成本,需要額外的投資跟時間累積。


##結論

其實去年也參加過了,心得一樣,資料科學的技能要持續,不然就是 nothing  n! o! t! h! i! n! g!

(只是一年了,還是覺得自己很廢廢的 XD)

2015年9月4日 星期五

git commit 時用 vi 編輯儲存時出現 Error...

不知道為什麼我的 Mac 在操作 git 時,打 commit 後 :wq (儲存離開),會出現這樣的 Error:
➜  erp git:(master) git tag -a v1.1.1
error: There was a problem with the editor 'vi'.
Please supply the message using either -m or -F option.

這個 Error 很慘,表示我剛剛打的 commit 都不見了,所以也沒辦法有下一步 (push) 的動作。

在網路上有找到一個很奇怪的解法,要我把 git  預設使用的編輯器的 bin 路徑改掉,只要下這樣的 command 就可以正常 git comment:
➜  erp git:(master) git config --global core.editor /usr/bin/vim
很神奇... 如果有人知道為什麼請告訴我 TT。

2015年8月30日 星期日

Laravel PHP 5.6 mail stream_socket_enable_crypto

今天在用 Laravel 使用寄信時一直遇到這個問題: stream_socket_enable_crypto(): Peer certificate CN

查了一下才知道自己的 php 版本是 php 5.6,好像是改變了一些機制,看起來很複雜,不過快速的方式就是,如果你跟我一樣不是用 SSL,那可以把 'encryption' 的設定改為 '' 空值就好。

預設為 //'encryption' => 'tls',,改為 'encryption' => '', 或是 'encryption' => env('MAIL_ENCRYPTION', ''),

有空再來了解,蠻煩的,因為最近專案全面使用 php 5.6 以上,沒遇過這些問題,本來 SMTP 是一件這麼簡單的事情,搞的我心煩。

參考文章 https://laracasts.com/discuss/channels/general-discussion/smtp-mail

2015年8月21日 星期五

SCP 下載遠端 server 上的檔案

複製 AWS  ubuntu 上的檔案到自己的本機,可以使用 SCP 指令。

要看完整的 scp (secure copy) 指令就 man 一下吧 (man scp)。


如果你是要用 pem 去登入的話:
公式:
scp -r -i [pem file path]  user@host:[server folder path] [local destination path]

範例:
scp -r -i your_server.pem  ubuntu@ip_or_domain:/var/www/XXXX/  /tmp/目的地資料夾


-r 是遞迴的意思,因為複製的檔案可能是好幾層的資料夾。
-i 是 identity_file 的意思,所以後面的參數就是接 pem 檔的路徑。


因為每次都忘記,所以特別紀錄一下。

2015年8月6日 星期四

關於 Laravel 5.1 的 Middleware

接觸 Laravel 5.1 的時候看到 middleware 這個資料夾的時候真的有驚訝到,是說,正常人第一眼看到 middleware 的時候會有以下症狀:

* middleware 是什麼?
* 我該怎麼用 middleware?
* 不會寫會怎麼樣嗎? (<- 一定不會怎樣,看你對自己的要求到哪而已 XD)
* 乾眼症

本魯心中也是這兩個問號,不過還好,在剛進敝公司的時候,跟隨同事用 Koa (一個 node.js 的 web framework) 開發 Web Application 的時候,就已經接觸過 Middleware 這個玩意兒了,他說起來確實有點難解釋,抽象,但漸漸抓到它的用處之後,會覺得他真的很好用,使用它最著名的範例,像是 csrf, 權限管理, auth...,下面我會貼上一個 link,大家可以稍微去參考一下那個作者怎麼使用 middleware 做權限管理 (年紀越大越懶得把整份 code 都貼出來講...)。

我先拉回來繼續講 middleware 本身。middleware 有的書會翻中介層,有的會翻中介軟體。它本身的行為可以說是 filter (過濾器),他本身的功能,用意是來隔離網站基礎設施與業務邏輯,至於他的工作範圍,可以說是收到 http request 之後一直到業務邏輯這一段都算,你可以想像你在切一顆洋蔥,那一刀要切下去的時候,就是開始發送 http request,切到中心點時,就是 app 本身的核心功能 (MVC),中間這一段過程,都是 middleware 可以處理事情的地方。

所以那個過程,可以攔截很多資訊,像是在程式還沒跑到 view 時,就先判斷誰有資格看到那個 view,所以這樣的權限功能,就可以寫在 middleware,而不是已經進到 controller 甚至是 view 了,才開始做這些判斷,你一個 app 可能 50 個 controller,難道你要一隻一隻程式各別去加那個判斷嗎? 所以,試著把這些功能抽出來,寫到越前面(底)的地方,提早執行, 不符合條件繼續往下一步就早點 response 回去給 user。

假如今天我寫了一個 middleware,在每個 route 去設定 middleware 以及要 filter 的規格,這樣就算是有用到 middleware 的功能了,不過這樣的設計,或許還可以再更好一點,換言之,我覺得其實 middleware 就是在寫業務邏輯跟流程控制,只是讓他早點發生 XD。(有些文章認為,為每個 route 去設定 middleware 不是很好的設計。)


範例
這裏有篇 Laravel 5 Simple ACL manager 請參考 (這只是個有用到 middleware 的 sample,可以大概看一下,你不要照 copy,除非你要的功能跟邏輯跟他一樣。)。如果你不喜歡這個範例,下面參考也有其他 link。


範例邏輯說明
* 要寫 middleware,首先你要有隻 middleware (你也可以用 php artisan make:middleware 來產生空的檔案,預設 middleware 會放在 app/Http/Middleware ),以上面那個範例來說,作者建立了一隻 CheckRole 的 middleware。
* 在 kernel.php 去註冊你的 middleware (不然誰知道你有 middleware 呢?),註冊的 key 就是使用 middleware 的名稱,如:  'roles' => 'App\Http\Middleware\CheckRole', 使用 middleware 時就是用 roles 那個名字。

放在 App\Http\Kernel.php 的 middleware,算是 global 或是 application 層級的 middleware。 -  翻自 『To add a global or application level middleware, we use the $middleware property of the App\Http\Kernel class.』- Laravel 5 Middleware Stack Decoded 
Route level middlewares can be registered using the $middleware property of the App\Providers\RouteServiceProvider class. - 參考自 Laravel 5 Middleware Stack Decoded 
* 在 middleware 把規則寫出來,做流程控制,哪時候可以通過這個 middleware (return $next($request)),哪時候不行通過,吐個 401 或是 402 跟使用者說掰掰之類的...。
* 在路由控制 (route) 做 middleware,哪幾個 route 需要經過你的 middleware 都要列出來,或者,你也可以把 route 做群組 (group) 之後,再設定 middleware。


小結論
* 合理的使用 middleware。(<- 純嘴砲,我也不知道怎樣算合理?!)
* middleware 也要注意程式有 Exception 的情況。
* 本篇只是小心得,希望大神路過指教 :) 有錯就鞭
* 其實我私心的覺得 L5 把 middleware 變得更好理解一點了,可是 code 比較多,在學 koa 的時候 code 少少的,只要 app.use() 一下就好,可是當時在學的時候,比較難理解...。

參考
https://docs.djangoproject.com/en/1.6/topics/http/middleware/
http://koa.rednode.cn/ 請參考 middleware 那邊有張圖。
http://www.richardbagshaw.co.uk/laravel-5-middleware/
http://www.codeheaps.com/php-programming/laravel-5-middleware-stack-decoded/
http://blog.elliothesp.co.uk/coding/passing-parameters-middleware-laravel-5/

2015年8月5日 星期三

Laravel 5.1 測試時模擬 user 登入

最近這幾天都在寫測試,花蠻多時間的,不熟之外,資源也不夠齊(不好找,有時 L4, L5 參雜,自己都搞混了)。

如果你是用 Laravel 4,那麼請參考 4 的說明 (有一段:『 You may set the currently authenticated user using the be method』從這邊開始 )。

在 Laravel 5.1 測試 user 登入狀態,要用 Model Factories 的方式,在這裡也要感謝小鐵大大,幫了我很多忙 :P。


大概的重點如下
* 在 phpunit 測試 code 裡面,使用 factory 去 fake 一個 $user,如官方文件說明,看你想要用 make() 還是 create()。另外我也意外地發現 $faker 蠻方便的,很開心的在 database/factories/ModelFactory.php 盡量學習用 $faker XD

我的 sample code,不是很完美,大概描述一下作法類似這樣子而已:
因為之後有很多模組或是功能都會需要這個假裝有 user 登入的測試情況,所以把它寫在外面 (TestCase去),繼承 TestCase 的測試 php 就都可以使用。
// TestCase.php

protected function demoUserLoginIn()
{
    $user = factory(App\User::class)->make();
    // Use model in tests...
    // 登入 user
    $this->be($user);
}

繼承 TestCase 的測試程式:
//  某隻 extends 自 TestCase 的測試.php

public function testLogout()
{  
    // 使用 TestCase 的 demoUserLoginIn
    $this->demoUserLoginIn();

    // 檢查登入狀態
    $this->assertTrue(Auth::check());
    // do other things...
}

* 另外一種測法是,只是測試資料帶入 form 然後登入的情況,一樣也可以模擬出登入的情況,只是每次都要繞到登入頁,這種測法就比較適合單純測登入表單的情況。

測試 form 登入,資料帶入 POST 的情況,要小心 csrf 的問題,還要在測試加上 Session::start();。
public function testLogin()
{
    Log::info('testLoginSuccess');
      Session::start();
    
    $this->call('POST', '/login', [
        'username' => 'winwuloveyou',
        'password' => '123456',
        '_token' => csrf_token(),
    ]);

    $this->assertRedirectedTo('dashboard');
}


參考
書目:「Basic TDD in Laravel 5」作者: Jace Ju.
Testing Laravel 5 Routes with CSRF Protection Using PHPUnit
https://laracasts.com/series/whats-new-in-laravel-5-1/episodes/5


2015年8月3日 星期一

Laravel 設定 foreign 要注意的事情

設定 FOREIGN_KEY_CHECKS
(1) 如果你在有設定 foreign 的相關 table 做 seeder 的時候,假設出現以下的 error: SQLSTATE[42000]: Syntax error or access violation: 1701 Cannot truncate a table referenced in a foreign key constraint ....

會有這樣的問題是因為 seed 的時候,就會立刻去檢查某個 schema 的外鍵,可是外鍵當時可能還沒建立。

那表示你需要在 seeder 在 inser 資料前後,做 FOREIGN_KEY_CHECKS 的切換 (畫底線那兩行),inser資料前先設為 0,insert 資料後設為 1 :

// 假設這是某隻 seeder 
// 這隻 seeder 的某個欄位是別張表的外鍵 
// XXXXTableSeeder.php

<?php

use Illuminate\Database\Seeder;
class UserTableSeeder extends Seeder
{
    public function run()
    {
        // disable foreign key constraints
        DB::statement('SET FOREIGN_KEY_CHECKS = 0');
        DB::table('user')->truncate();
        $users = [
               // data....
        ];
         DB::table('user')->insert($users);
        // disable foreign key constraints
        DB::statement('SET FOREIGN_KEY_CHECKS = 1');
    }
}


小心,unsigned()!
(2) 『當外鍵有參照到自動增量時,記得設定外鍵為 unsigned 型態。』- from http://laravel.tw/docs/4.2/schema
這句話的意思是,如果某張表的 key 是參考到另一張表的鍵而且是 auto_increment 時,要記得將那個外鍵設定為 unsigned()

範例,假這個 id 會在別的 table 某欄位參考到,那麼就要記得 unsigned:
$table->increments('id')->unsigned();

這是比較多新手會忘記的地方。

phpunit 跑 SQLite
(3) 補充一下關於 (1) FOREIGN_KEY_CHECKS 這件事情,因為在 phpunit 測試 ORM 時,有時會用 sqlite 而不是 MySQL,如果照樣使用 (1) 的 FOREIGN_KEY_CHECKS 的方式會報錯,另外也不建議使用 DB::enableForeignKeyCheck() 或是 DB::disableForeignKeyCheck() (這是我從 issue 找到的方法....),試一下發現 sqlite 一樣看不懂,而且還會噴出這樣的錯誤:  rrorException: call_user_func_array() expects parameter 1 to be a valid callback, class 'Illuminate\Database\SQLiteConnection' does not have a method 'disableForeignKeyCheck'

所以我目前找到比較好的方式(可以 mysql 跟 sqlite 兩全其美) 就是把 (1) 改成這個樣子...我其實說不上來這樣的修改好不好,如果有快速,乾淨解法,拜託讓我知道 QQ
if (DB::connection() instanceof Illuminate\Database\SQLiteConnection) {
    DB::statement(DB::raw('PRAGMA foreign_keys=0'));
} else {
    DB::statement('SET FOREIGN_KEY_CHECKS = 0');
}

// insert data


if (DB::connection() instanceof Illuminate\Database\SQLiteConnection) {
    DB::statement(DB::raw('PRAGMA foreign_keys=1'));
} else {
    DB::statement('SET FOREIGN_KEY_CHECKS = 1');
}

2015 08-31 補充:

有時候在跑測試的時候,會出現 Illuminate\Database\QueryException: SQLSTATE[HY000]: General error: 1 near "SET": syntax error (SQL: SET FOREIGN_KEY_CHECKS=0),這也是因為測試時的 db 環境是 Sqlite,所以 check foreign 的方式也不太一樣。

https://laracasts.com/discuss/channels/general-discussion/sql-hy000-error-when-seeding-phpunit-tests
這邊有個參考作法,直接從 DatabaseSeeder 動手腳,感覺比較乾淨,用 DB::getDriverName() 的方法感覺也比 instanceof Illuminate\Database\SQLiteConnection 更適合。

如果再跑測試的時候遇到 SQLSTATE[HY000]: General error: 1 too many SQL variables
找了一下只知道是因為: this is a limitation of sqlite: 999 parameters.。解法還在找 :P

Laravel ORM 兩個 schema(cloumns) 一起 unique

在製作某個表時,發現有個 schema 是需要一起 unique 起來的。

比方說有張記錄使用者權限的表格,user winwu  同時有 article-write, 以及 article-read 兩個權限,就會有兩筆記錄:

id  user_account     user_auth
1   winwu                 article-write
1   winwu                 article-read

但是又不希望  winwu   article-write 有一天又被重複紀錄,就是 winwu 這個人,對應到 article-write 是 unique 的。

在 schema builder  (migration 檔案) 可以這樣表示:

$table->unique(['user_account', 'user_auth']);

記得,重跑 migrate:rollback,然後再重新 migrate,你可以在 seeder 試著故意重複兩次一樣的紀錄,應該就會有 error 告訴你這些 schema 是 unique 的了。

error的訊息會像這樣:
  [PDOException] SQLSTATE[23000]: Integrity constraint violation: 1062 Duplicate entry 'winwu-article-read' for key ...

參考:
http://stackoverflow.com/questions/16990723/laravel-4-making-a-combination-of-values-columns-unique

對了,如果有比較適合的方式可以達到一樣的功能,就麻煩留言一下讓更多人知道 :) 謝謝!

2015年8月2日 星期日

O'REILLY『可測試的 JavaScript』 讀書心得

(我好幾次呆坐在螢幕前,不知道該分享些什麼...)

第一次在書店看到這本書時還蠻興奮的,又是 JavaScript,又講測試,感覺就應該讀一下,立刻帶回家 XD (敗家)

幾個心得:
*測試是有方法可以遵循,有經驗可以參考,但是寫測試是要練出來的,只有自己練出來才是最真實的...。

 *  TDD (Test-Driven Development) 測試驅動開發,是敏捷開發的推薦做法,就是先寫測試,再寫相對應的程式。 

 * BDD (Behavior-Driven Development) 行為驅動開發,建立在 TDD 之上,測試描述一個程式或是模組的行為。 

*要測試你的程式碼,首先程式碼要先可以被測試才是重點,畢竟程式可以很複雜,也可以很簡單,可以測試的程式碼要盡量是低耦合, 獨立的。(多做程式的拆解練習,把複雜的程式慢慢拆解為一隻隻比較單純, 單一任務的程式)。

*第三章講的事件導向架構,我沒有看得很懂就是,但是重點跟上一點接近。

*第四章講單元測試,單元測試算是我第一次接觸測試的方式,他需要工程師去思考每個單元測試需要哪些測試案例(腦補一些可能出現的弱點,就好像某隻程式明明需要帶入一個 值為 email 的參數,但是只有測到這個參數帶進去,卻沒有測試 email 的格式是否正確之類的...),因此,單元測試算是不能百分之百找到 bug 的測試,但是單元測試的重點是在於測試每隻程式的功能是否有符合需求(功能確認導向)。
   另外單元測試的 code 我覺得蠻好讀的,他的重點就是斷言(assert),直接去驗證某個值是否符合預期。

* 程式碼涵蓋率(Code Coverage),用來測量已經執行的測試程式碼之於未執行過的程式碼的涵蓋數,結果會用百分比來表示。 通常跟單元測試有關。書中 P.95 有個涵蓋率的參考:
    - 低於 50% 的 code coverage,是個低標區 (red flag)
    - 介於 60%~80% 的 code coverage,是甜蜜區 (sweet spot)
    - 大於 80% 的 code coverage,單元測試的效能會符合收益遞減率(<- 基本上我看不懂這個意思是什麼) ( code coverage 過高可能有誤導之嫌)。
   另外,code coverage 最好是自動化產生。

* 測試環境的模擬,也是一個很重要的測試技能。也許你在測試某隻程式時,需要重新設定資料庫的狀態,或是某隻程式可能相依於另一隻程式(相依性,是單元測試不想要測試的部分,可以利用 mocks 或是 stubs)。

*  mocks 跟 stubs 的不同在於 mocks 用於命令, stubs 用於查詢(參考 p.95)
  
*  mocks 用來被驗證 function 正確呼叫外部的 api。

*  stubs  用來假造回傳值到需要被測試的 function。

*  Doubles (測試替身),用來模擬相依性所需要用的物件,他也可同時扮演 mock 或是 stub。

*  前端 JavaScript,可參考 PhantomJS, Selenium。因為這兩個,方向都很大,我也沒摸熟過,不方便提...

*  第六章講效能測試,瀏覽器效能測試可以參考 HAR,書中有說明如何產生 HAR 檔案,如何查看。負載測試(Load Testing)  最常聽到的就是 ab (Apache Bench)。

*  效能測試可以用來辨別會阻礙效能的瓶頸,負載測試用來測試程式可以處理多少事情。

最後,我是覺得剛接觸測試的話,可以翻翻這本書,但是不用帶著墨在書本範例的程式碼,概念上先瞭解一下,這本書用蠻多 YUI 的 code 來解說,大概看一下就好,只是像我這種沒用過 YUI 的人,會覺得有點失落 XDD,因為書本有時候會提到一些 solution 是針對 YUI 的解法,所以有時候也會蠻疑惑的 XD。

前陣子在工作上是使用 Mocha, Chai 寫測試,有空再來分享這一塊。

以前看到別人講測試會覺得有點複雜,工具太多,要測試的方法也很多,嘗試過 chai, mocha 之後我才漸漸了解,原來這些測試工具都是環環相扣的,而且很有可能會上癮,也許你單元測試寫完之後,你就會想了解 code coverage,然後你也會想要用一下 phantom 或是 selenium,然後測試的項目,就會越來越齊全...,也會越有成就感。



參考:


2015年8月1日 星期六

Laravel5 file upload 上傳檔案範例

我把 controller 的範例分兩個來看,一個是多檔上傳,一個是單檔上傳,也不是說寫得很好,但至少還可以 work。

多檔上傳的範例:
另外因為是 json 回傳,所以 ajax 的部分我就不說明了。


單檔上傳的範例:

另外我也描述一下 view 的 form:

範例裡面有兩個 Form::file,請選擇是用哪一種,一個是 photo,另一個是 photo[]。

你還可以多注意的事情
* 檔名的建立方式我通常偏好 uuid,這部分就是依個人喜好。
* 圖片的 crop, resize 在這個範例並沒有做,你也可以自己串。
* 如果你不是用 Form:: 的方式在 view 建立你的 <form> 等等標籤,那麼務必要記得 form 的這個 enctype="multipart/form-data" (在這個範例是透過 'files'=>'true' 屬性產生)屬性一定要有,否則你永遠沒有東西可以上傳
* 這邊沒有做 javascript ajax 的範例,所以如果你是沿用這個 sample,當然送出之後會接看到 json 格式的頁面,所以也是要自己把這段串起來,這邊我是為了方便,才先用 form submit。

參考
How To Create File Upload With Laravel By clivern On April 10, 2014
webpatser/laravel-uuid

2015年7月31日 星期五

Laravel 搜尋與分頁功能製作的一些心得

之前自學 Laravel 4 的時候,分頁跟搜尋做的真是...亂七八糟,知道亂七八糟是因為,知道了有更好的寫法,不然就是會一直停留在自己的已知。

後來這兩個月接觸 Laravel 5 之後,發現有些以前的寫法,可以寫得更好,比方說... 有些現成的 method,我沒發現以前可以那樣用之類的情況,還去網路上找了一些沒有必要的方法,所以打算先一些做紀錄 XD,描述一下大概的邏輯,不會把整份 code 把拿出來講,如果有其他做法也歡迎讓我知道。

我這邊所指的分頁跟搜尋,是以一般後台所需要的功能為主,文章可能會牽涉 controller, model 跟 view,畢竟一個搜尋,除了 ORM 要處理帶入的搜尋條件之外,也要影響分頁的顯示,還有排序等等情況要做。改天有空,我會再分享一篇前端用 ajax 撈 json 的分頁方式。


我們先從 ORM 說起吧,在沒有分頁之前,撈資料,建 Model 都是稀鬆平常的事,最常見的撈法就是整個全撈出來,像這樣:
$articles = Article::all();
這個全部撈出來的 $articles 變數,可能會放在 ArticleController 某個顯示列表的 method,我來假設那個 method 叫做 getIndex 好了,那麼 ArticleController 的 getIndex 會將 $news 的變數拋到某個 view 去:
// ArticleController.php

public function getIndex() {
    
    // ORM...
    // $articles = ....

    return view('article.index', ['articles' => $articles]);

}

接下來,來做一點複雜的情況,假設在 article.view 加了一個搜尋用的 Form 表單,讓 user 可以搜尋文章的作者(Author),文章的標題(Title),文章的流水號(Id)。假設 user 送出了那個表單,應該發生什麼事情?

(1) 如果是用 GET  method 送出表單,網址應該呈現 localhost/article?author=winwu&title=&id=&sort=id&order=desc

(2) view 得到的資料要是正確的

(3) 資料超過某個數量後,要顯示分頁

先來解決 (1),當搜尋的條件已經進到頁面時,ORM 就需要做一些改變,首先我會在 controller 決定我願意接受的搜尋條件參數: (簡單來說其實就是接 $_GET 參數啦! 只是我現在 focus 在 Laravel 上。)
$queryString =  Request::only([ 'id', 'author', 'title', 'order', 'sort]); 
接到 GET 參數後,接下來,需要把條件,帶到 ORM 的搜尋表達上,在這邊,我個人比較偏好 where 帶 $query 方式去做搜尋,因為比較彈性,也可以在 function 下一般的 if else 或是一些商業邏輯的判斷, 資料轉換:
// default desc
$order = (isset($queryString['order']) && ($queryString['order'] === 'asc')) ? 'asc' : 'desc';

// defaul sort
$sort = (isset($queryString['sort'])) ? $queryString['sort'] : 'id';

$articles = Article::where(function($query) use ($queryString) {


if (isset($queryString['id']) && $queryString['id'] !== "" ) {
$query->where('id', '=',  $queryString['id'] );
}

if (isset($queryString['author']) && $queryString['author'] !== "" ) {
$query->where('author', 'LIKE', '%' . $queryString['author'] . '%');
}
        // do other things 
        
}) // 如果你需要 join 其他表,可以接在這裡: 
   /*
      -> join('other_table', function ($join) {
          $join->on('article.id', '=', 'other_table.reference')
      })     
   */;

// 處理order, sort 以及分頁數量設定 10 筆為一頁
$articles =  $articles->orderBy($sort, $order)->paginate(10);
分頁筆數的部分,建議也可以拆出去用變數傳入。
(1) 的部分,算是到一個段落了。


接下來,處理 (2)。
view 就只有兩件事,兩件事都可以簡單,也可以複雜。
(2-1) 顯示分頁
(2-2) 列表的表格 tr th 上,要有排序的功能可以點按。

(2-1) 相對單純,pagination 只要看官方文件即可,顯示方式也跟 orm 那邊的設定有關,如果你是用 ->simplePaginate(10) 那就只會呈現只有上一頁, 下一頁的分頁顯示,如果是 ->paginate(10),就會顯示比較完整的分頁。

顯示分頁,要在 article.view 加上 {!! $articles->render() !!} ,就會顯示出分頁了,這就是 (3) 。

不過這裡有個問題要注意,當我已經有搜尋某個條件之後,點到分頁的第二頁,原本的 query string 並不會帶到第二頁去,網址只會變成  localhost/article?page=2  而不會是  localhost/article?author=ssss&title=&id=&sort=id&order=desc&page=2

這怎麼辦呢,有個好用的 method 叫做 appends(),可以把當下頁面上的搜尋條件參數,帶到分頁 link 的 url 上,你可以參考文件的 Appending To Pagination Links,或是像我一樣操作在 ORM 上。

我加上了 appends 到 articles 上。
$articles =  $articles->orderBy($sort, $order)
                                ->paginate(10)

                                ->appends($querystringArray);
因為我把 appends 這個項目加在 ORM 上,所以我的 view 的  {!! $articles->render() !!}  完全不用調整。你可以挑一個做法來用。

(2-2) 的話,排序 icon 大部份都是採用 bootstrap 的 icon 或是 font-awesome,麻煩就在這個排序的按鈕跟分頁其實是有些類似的,他一樣要帶入當下的搜尋條件,除了 order 跟 sort 要改變。

這個部分我至今也沒有很好的解法,但一直寫類似的 code,有些麻煩,後來我把這塊的 html 拆出去寫成兩個 function (這兩個 function 可以寫在 article.index 的 view 的最上方,好一點的做法就是拆出去一個 class 去包裝他 )

function getArticleSortLinks($sortField) {
  $sortLinks = route('article.index',
array(
     'sort'      => $sortField,
     'order'    => (isset($_GET['order']) && $_GET['order'] == 'desc') 
                                  ? 'asc' : 'desc',
     'id'          => isset($_GET['id']) ? $_GET['id'] : '',
     'author'  =>  isset($_GET['author']) ? $_GET['author'] : '',
     'title'       =>  isset($_GET['title']) ? $_GET['title'] : ''
     ));
     return $sortLinks;
}

function getSortIcons($sortField) {
  /*
     這個寫法的 else 會有一些問題,但就簡單參考一下。
   
     如果當下的排序是遞減,那個 icon 就要切換成遞增,反之。

     然後預設我是擺 asc。
   */

  if (isset($_GET['sort']) && ($_GET['sort'] == $sortField)) {
    $sortLinkIcons = ''
    . 'fa fa-sort-amount-'
    . ( (isset($_GET['order']) && ($_GET['order'] == 'desc')) ? 'asc' : 'desc');
  } else {
    $sortLinkIcons = ''
    . 'fa fa-sort-amount-asc';
  }
  
  return  $sortLinkIcons;
}

接著在排序的按鈕使用這個 function: (只舉某個欄位當作例子)
<th>文章標題
    <a href="{{ getArticleSortLinks('title')}}">
          <span class="{{ getSortIcons('title')}}"></span>
    </a>
</th>

大概是這樣,有想到什麼我會再補充。
另外根據經驗,如果 ORM 需要 join 到三張表以上,會變得蠻慢的... QQ。

下週還會跟公司的架構師做一些 code 的調整,有什麼我覺得一定會修正的部分,我會再補上來 :P

2015年7月30日 星期四

Laravel phpunit 報錯 Cannot redeclare .. previously declared ...

今天在 laravel 的專案下跑 phpunit 突然報了一堆 [Symfony\Component\Debug\Exception\FatalErrorException] 的錯誤。

可能的原因有很多。

以我的問題來說,一追才知道原來是因為我在 blade.php 的 view 下,寫了兩隻現成的 function,但是 phpunit 不能這樣做,測試被執行之後,重複執行相同的函數,就等於函數被重新定義,所以好方法就是,還是得乖乖的把這兩個 function 封裝到某個 class 下。

原本我的 xx.blade.php 是這樣:
function myViewHelper() {
      return ...;
}

<a href="{{ myViewHelper() }}">Go!</a>

最後我寫了一支類似 helper 或是 service 的 php,把 class use 進來,再 call 那個 function,得救 :P 。

類似這樣:
use XXX\XXX\ myViewHelper as myViewHelper;

<a href="{{ myViewHelper::getSortLinks()  }}">Go!</a>


應該還有更好的方式,可能 use 不應該放在 view(xx.blade.php) 的檔案裡,不過重點就是... 不能直接定義 function 在 view 裡。



2015年7月21日 星期二

homebrew 升級 PHP56

1. 先 tap hombrew-php
brew tap homebrew/homebrew-php

2. 安裝 php56 (我沒有刻意移除過去的存在的 php55版本)(安裝需要一點時間)
brew install php56

3. 修改你的檔案 .profile, .zshrc, .bashrc 或者 .bash_profile,看你用哪一種,加入以下的 export $PATH:
export PATH="$(brew --prefix homebrew/php/php56)/bin:$PATH”

4. 重新 source  .profile, .zshrc, .bashrc 或者 .bash_profile:
像我是用 .zshrc:
source ~/.zshrc

2015年7月15日 星期三

[chai]The ChromeDriver could not be found on the current PATH

在使用 chai 的 webdriver 時出現了一點問題,其 demo code 如下,基本上同官方網站:
// test/index.js
var sw = require('selenium-webdriver');
var chai = require('chai');
var chaiWebdriver = require('chai-webdriver');

// Start with a webdriver instance:
var driver = new sw.Builder()
  .withCapabilities(sw.Capabilities.chrome())
  .build();

// And then...
chai.use(chaiWebdriver(driver));

// And you're good to go!
driver.get('http://github.com');
chai
  .expect('#site-container h1.heading')
  .dom.to.not.contain.text("I'm a kitty!");

然而在執行的時候出現這個問題:
node test/index.js
XXXX/node_modules/selenium-webdriver/chrome.js:54
        'http://chromedriver.storage.googleapis.com/index.html and ensure ' +
                                                                            ^
Error: The ChromeDriver could not be found on the current PATH. Please download the latest version of the ChromeDriver from http://chromedriver.storage.googleapis.com/index.html and ensure it can be found on your PATH.
    at Error (native)
而且其實我的 chromeDriver 已經是最新版了...

後來在 stackoverflow 找到了這個解法,還蠻有用的:
http://stackoverflow.com/questions/27733731/passing-requirechromedriver-path-directly-to-selenium-webdriver

修改結果如下:
var sw = require('selenium-webdriver');
var chai = require('chai');
var chaiWebdriver = require('chai-webdriver');

// Start with a webdriver instance:
var chrome = require('selenium-webdriver/chrome');
var path = require('chromedriver').path;

var service = new chrome.ServiceBuilder(path).build();
chrome.setDefaultService(service);

var driver = new sw.Builder()
    .withCapabilities(sw.Capabilities.chrome())
    .build();

// And then...
chai.use(chaiWebdriver(driver));

// And you're good to go!
driver.get('http://github.com');
chai
  .expect('#site-container h1.heading')
  .dom.to.not.contain.text("I'm a kitty!");

FYI.


2015年7月13日 星期一

用 safari 照相一直 crash 的一種解法

http://stackoverflow.com/questions/27763729/iphone-ios-8-buffer-limit-on-html5-media-capture

2015/07/31 補充:
這個問題後續有些想法,因為手機照相,我跟我朋友有個結論是,iphone 6 以下都沒有問題,初步猜測,也許是因為 iphone6 拍出來得照片太大,在轉換 base64 之後太大,導致 safari crash...

Vue multiselect set autofocus and tinymce set autofocus

要在畫面一進來 focus multiselect 的方式: 參考: https://jsfiddle.net/shentao/mnphdt2g/ 主要就是在 multiselect 的 tag 加上 ref (例如: my_multiselect), 另外在 mounted...