參考 http://stackoverflow.com/questions/42057797/laravel-5-4-artisan-migrate-fails-with-call-to-undefined-method-dispatch。
如果升級時,執行 php artisan 相關指令沒事,就不用理會這個。但如果出現類似錯誤,先把 bootstrap/cache 底下的檔案都刪掉,然後執行
php artisan cache:clear
php artisan view:clear
2017年2月13日 星期一
2016年5月16日 星期一
Laravel 利用 orderByRaw 針對欄位順序排序
Laravel 的 orderBy 雖然可以多個下來 order, 但感覺這樣的 order 也只是以字串的開頭排序,而我要的是根據裡面是否有符合我要的字串,若有則依照欄位不同排序
如:
假設搜尋 class 跟 teacher 這兩個欄位有 "明" 這個字,但是所有的搜尋結果,要以 class 優先排序,再出現 teacher 的結果。
類似:
參考:
http://stackoverflow.com/questions/6243678/specific-ordering-sql-command
Order by using multiple columns and manually array field in Laravel? By Itsolutionstuff
Laravel 5 orderByRaw 绑定参数问题
http://stackoverflow.com/questions/4798000/mysql-order-by-keyword-match
如:
假設搜尋 class 跟 teacher 這兩個欄位有 "明" 這個字,但是所有的搜尋結果,要以 class 優先排序,再出現 teacher 的結果。
類似:
return $result
->orderByRaw('CASE WHEN `class ` LIKE \'%' . $query['query'] . '%\' THEN 0 ELSE 1 END ASC, id DESC')
->paginate($pageNumber);
參考:
http://stackoverflow.com/questions/6243678/specific-ordering-sql-command
Order by using multiple columns and manually array field in Laravel? By Itsolutionstuff
Laravel 5 orderByRaw 绑定参数问题
http://stackoverflow.com/questions/4798000/mysql-order-by-keyword-match
2016年5月2日 星期一
修正 laravel: Relationship method must return an object of type Illuminate\Database\Eloquent\Relations\Relation
應該是呼叫 model 方法是不正確
檢查是不是呼叫一個方法,如果是,改為加上 ( )
(如 $this->save 應該改為 $this->save() )
參考:
http://stackoverflow.com/questions/23773467/laravel-relationship-method-must-return-an-object-of-type-illuminate-database-e
#我不會寫code但我會google
檢查是不是呼叫一個方法,如果是,改為加上 ( )
(如 $this->save 應該改為 $this->save() )
參考:
http://stackoverflow.com/questions/23773467/laravel-relationship-method-must-return-an-object-of-type-illuminate-database-e
#我不會寫code但我會google
2016年4月25日 星期一
Laravel update form 如果是 Unique 欄位驗證檢查如何排除當下更新的該筆記錄
use laravel 5.
when we update an form, example: "member" table.
and we want the email field should be unique on this table.
when we update an form, example: "member" table.
and we want the email field should be unique on this table.
2016年2月28日 星期日
laravel 一個 input 的值同時用來搜尋多個 column
如: 同一個 search input 的值想要搜尋好幾個欄位,可以用 whereNested。
Example:
if (isset($query['query']) && $query['query'] !== "" ) {
$q->whereNested(function($seq) use ($query) {
$seq->orwhere('name', 'LIKE', '%' . $query['query'] . '%');
$seq->orwhere('subject', 'LIKE', '%' . $query['query'] . '%');
$seq->orwhere('address', 'LIKE', '%' . $query['query'] . '%');
$seq->orwhere('description', 'LIKE', '%' . $query['query'] . '%');
}, 'and');
}
不確定有沒有更好的方式。
參考 http://stackoverflow.com/questions/15167770/laravel-eloquent-search-two-optional-fields
Laravel 5 以上請參考:
https://laravel.com/api/5.2/Illuminate/Database/Query/Builder.html#method_whereNested
Example:
if (isset($query['query']) && $query['query'] !== "" ) {
$q->whereNested(function($seq) use ($query) {
$seq->orwhere('name', 'LIKE', '%' . $query['query'] . '%');
$seq->orwhere('subject', 'LIKE', '%' . $query['query'] . '%');
$seq->orwhere('address', 'LIKE', '%' . $query['query'] . '%');
$seq->orwhere('description', 'LIKE', '%' . $query['query'] . '%');
}, 'and');
}
不確定有沒有更好的方式。
參考 http://stackoverflow.com/questions/15167770/laravel-eloquent-search-two-optional-fields
Laravel 5 以上請參考:
https://laravel.com/api/5.2/Illuminate/Database/Query/Builder.html#method_whereNested
2015年9月30日 星期三
Laravel 在 Eloquent alias table 名稱
在 Laravel 撈資料的時候發現有時候 Eloquent 很不好組,尤其是有 sub query 的時候....,後來用了 DB 的方式去做 Query:
但我後來發現原來 alisa 在 Eloquent 有方法耶...
在 Eloquent 使用 Alias,只需要使用 from 的這 static method,比方說上面那一句可以改成下面這一句,後面的 where 幾乎是沿用就可以了。
$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)'
)
)
->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 的方法取資料。$query-> where(
'xxx_xxxx.GG, '=',
DB::raw(
'(select max(GG) from xxx_xxxx as b where xxx_xxxx.`no` = b.no)'
)
);
2015年9月22日 星期二
『在 PHP 上學會自動化測試與實戰 TDD』 ... 下課後
前言
我自己剛開始在使用 phpunit 遇到的一些問題: (嚴格來說也不能說奇怪... 要說自己涉世未深..)
1. 效能問題 (越跑越慢, 甚至慢的奇怪).
2. Database 沒有設定好,設定錯誤導致應該要以 SQLite 而不小心跑成 MySQL.
3. 類別的 Mock 不會寫.
4. tearDown 的地方有時候會忘記.
5. 測試碼太多支時,會有點不知道怎麼組織
6. 會丟 Exception 的 function 不知道怎麼測,又不希望被標成 risky tests (phpunit 如果發現你的 測試 function 根本沒有 assert 時會出現的訊息)
7. 知道的 assert 太少 (雖然這完全是沒唸書的關係...)
第一天講單元測試, unit test 算是很小的單元,一次只做一件事情的測法,這個算是剛學習測試最好上手 and 理解的。再來一些原則,像是 3A ... 還有教到一些重構,因為寫測試的時候,難免會邊重構, 邊寫測試,所以學測試,跟重構也有一點關係。(我也想起自從開始學 TDD 之後,也會開始對重構很有興趣,這真的是不知道為什麼 XD) 因為這堂課的關係,我才發現 phpstorm 好棒啊! 這些 refactor 的功能 sublime 都沒有.. 雖然有些殘念,不過接下來可以在專案重構時,也趁機學學使用 phpstorm。
另外 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年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
查了一下才知道自己的 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月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。
* 在路由控制 (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/
* 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 那個名字。
* 在 middleware 把規則寫出來,做流程控制,哪時候可以通過這個 middleware (return $next($request)),哪時候不行通過,吐個 401 或是 402 跟使用者說掰掰之類的...。放在 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
* 在路由控制 (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 的測試程式:
* 另外一種測法是,只是測試資料帶入 form 然後登入的情況,一樣也可以模擬出登入的情況,只是每次都要繞到登入頁,這種測法就比較適合單純測登入表單的情況。
測試 form 登入,資料帶入 POST 的情況,要小心 csrf 的問題,還要在測試加上 Session::start();。
參考
書目:「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
如果你是用 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);
}
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...
}
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');
}
{
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 :
小心,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
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
(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');
}
}
// 這隻 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');
}
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 檔案) 可以這樣表示:
記得,重跑 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
對了,如果有比較適合的方式可以達到一樣的功能,就麻煩留言一下讓更多人知道 :) 謝謝!
比方說有張記錄使用者權限的表格,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月1日 星期六
Laravel5 file upload 上傳檔案範例
我把 controller 的範例分兩個來看,一個是多檔上傳,一個是單檔上傳,也不是說寫得很好,但至少還可以 work。
範例裡面有兩個 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
多檔上傳的範例:
另外因為是 json 回傳,所以 ajax 的部分我就不說明了。
另外因為是 json 回傳,所以 ajax 的部分我就不說明了。
單檔上傳的範例:
另外我也描述一下 view 的 form:
另外我也描述一下 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 都是稀鬆平常的事,最常見的撈法就是整個全撈出來,像這樣:
接下來,來做一點複雜的情況,假設在 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 上。)
(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 上。
(2-2) 的話,排序 icon 大部份都是採用 bootstrap 的 icon 或是 font-awesome,麻煩就在這個排序的按鈕跟分頁其實是有些類似的,他一樣要帶入當下的搜尋條件,除了 order 跟 sort 要改變。
這個部分我至今也沒有很好的解法,但一直寫類似的 code,有些麻煩,後來我把這塊的 html 拆出去寫成兩個 function (這兩個 function 可以寫在 article.index 的 view 的最上方,好一點的做法就是拆出去一個 class 去包裝他 )
接著在排序的按鈕使用這個 function: (只舉某個欄位當作例子)
大概是這樣,有想到什麼我會再補充。
另外根據經驗,如果 ORM 需要 join 到三張表以上,會變得蠻慢的... QQ。
下週還會跟公司的架構師做一些 code 的調整,有什麼我覺得一定會修正的部分,我會再補上來 :P
後來這兩個月接觸 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]);
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);
分頁筆數的部分,建議也可以拆出去用變數傳入。$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() !!} 完全不用調整。你可以挑一個做法來用。->paginate(10)
->appends($querystringArray);
(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;
}
$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;
}
/*
這個寫法的 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>
<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 是這樣:
類似這樣:
可能的原因有很多。
以我的問題來說,一追才知道原來是因為我在 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 。return ...;
}
<a href="{{ myViewHelper() }}">Go!</a>
類似這樣:
use XXX\XXX\ myViewHelper as myViewHelper;
<a href="{{ myViewHelper::getSortLinks() }}">Go!</a>
應該還有更好的方式,可能 use 不應該放在 view(xx.blade.php) 的檔案裡,不過重點就是... 不能直接定義 function 在 view 裡。<a href="{{ myViewHelper::getSortLinks() }}">Go!</a>
2015年6月5日 星期五
Laravel stdClass Object 轉 Array
(我想我最近已經寫 code 寫到不知道在幹嘛了...)
在使用 Laravel 的時候,從 DB (Mysql) 拿資料出來時,你可以透過 PDO Fetch style 去改變拿出來時的型態(取 ASSOC 或是 CLASS),這時候只要改變 database 的 config 就可以了(參考),又或者你只有某一部份的 sql 需要改變 PDO Fetch style,那你也可以單獨寫設定在程式裡,記得在結束後把設定改回來:
另外一個情境是,我的資料是先預先存在 Redis 裡面,如果 Redis 取不到資料,就會跟 Mysql 要,拿到資料後再 json_encode 塞到 Redis,但是這兩者取出的資料格式會變成 stdClass v.s Array,麻煩的是我希望 Redis 取出的格式是跟著 Mysql 的,所以是 Reids 的 stdClass 要轉為 Array()。

要讓 redis 取出的格式跟 mysql 一樣都是 array 的話,
在 json_decode 時要記得加第二個參數 true 就可以讓他以 Array 的方式回傳了:
end.
在使用 Laravel 的時候,從 DB (Mysql) 拿資料出來時,你可以透過 PDO Fetch style 去改變拿出來時的型態(取 ASSOC 或是 CLASS),這時候只要改變 database 的 config 就可以了(參考),又或者你只有某一部份的 sql 需要改變 PDO Fetch style,那你也可以單獨寫設定在程式裡,記得在結束後把設定改回來:
// 參考自 http://stackoverflow.com/questions/26174267/convert-laravel-object-to-array
// 改變 PDO 的 style
DB::setFetchMode(PDO::FETCH_ASSOC);
// array of arrays instead of objects
DB::table(..)->get();
// 改回原本的 PDO style
DB::setFetchMode(PDO::FETCH_CLASS);
// 改變 PDO 的 style
DB::setFetchMode(PDO::FETCH_ASSOC);
// array of arrays instead of objects
DB::table(..)->get();
// 改回原本的 PDO style
DB::setFetchMode(PDO::FETCH_CLASS);
另外一個情境是,我的資料是先預先存在 Redis 裡面,如果 Redis 取不到資料,就會跟 Mysql 要,拿到資料後再 json_encode 塞到 Redis,但是這兩者取出的資料格式會變成 stdClass v.s Array,麻煩的是我希望 Redis 取出的格式是跟著 Mysql 的,所以是 Reids 的 stdClass 要轉為 Array()。

要讓 redis 取出的格式跟 mysql 一樣都是 array 的話,
在 json_decode 時要記得加第二個參數 true 就可以讓他以 Array 的方式回傳了:
json_decode($redis->get('key'), true);
老實說要不是因為發現 redis 取出之後型態不同,我還真的沒發現 json_decode 的第二個參事就是 assoc 的意思,只是預設是 false :P。原來一個簡單的參數就可以解決我的問題,差點還以為要上網找一些奇怪的 method 來轉換 :P 感謝天end.
2015年5月11日 星期一
Laravel On Ubuntu 環境建置指令紀錄 (Apache + MySQL + PHP5)
一早上班就遇到很慘的事情,aws 連不進去,public key 找不到,之前也沒有 snapshot 起來,結果也只能開新的 instance。
也不是用 docker,開新 server 最煩的就是環境建置,一氣之下乾脆把安裝步驟都記起來,以免下次又要重建...,重新 google 很花時間成本。 QQ
Server 背景與用途說明:
1. 一般 web server,aws 的 micro instance,作業系統 Ubuntu 14.04.1 LTS
2. 用的是 Apache + MySQL + php (皆獨立開分安裝)
3. web framework 用的是 Laravel 4.2
4. 用 80 port 而已
Step:
$ sudo apt-get update
// 安裝 git
$ sudo apt-get install git
// 安裝 apache
$ sudo apt-get install apache2
// 安裝 mysql , php, 還有 php 需要用到的 mcrypt, 相關模組
$ sudo apt-get install mysql-server php5-mysql
$ sudo apt-get install php5 libapache2-mod-php5 php5-mcrypt
$ sudo apt-get install openssl
$ sudo apt-get install curl
$ sudo php5enmod mcrypt
$ sudo service apache2 restart
$ sudo apt-get install php5-cli
// 安裝 redis,裝完後要使用的話,記得下 redis-server 啟用它
$ sudo apt-get install redis-server
// 環境確認 (php, apache, mysql 是否都存在)
$ php -v
$ which mysql
$ which apache2
// mysql 連線測試
$ mysql -uroot -p你的mysql密碼
// 安裝 composer
$ curl -sS https://getcomposer.org/installer | php
// 測試 composer 安裝正常
$ composer
ubuntu@ip-XXX-XX-X-XX:~$ composer
// clone 專案到 /var/www
這中間要 git clone 要自己注意 clone 的方式是 https 還是 ssh, 如果是 ssh 要記得加入server的 ssh public key 到 git(端看你用什麼方式 git clone,我是 bitbucket)
*備註: 產生 ssh key $ ssh-keygen -t rsa
會問你一些問題,不知道就一直 enter 下去。 把 id_rsa.pub 內容複製到 git/bitbucket 的 development key 管理的地方
$ cat ~/.ssh/id_rsa.pub 然後貼到設定檔去
$ cd /var/www
$ git clone git@XXX.xxx:team/repo-name.git
或者
$ git cloen https://XXX 用打帳號密碼的方式下載
//clone 完成後,cd 專案的資料夾
$ cd /var/www/repo-name
// 先進行 composer update 下載相依的 package
$ composer update
// 對 app/storage 做 777 或 755 的權限
$ sudo chmod 0777 -R storage/
// 如果要跑 migration 建立 table 的話,記得先建好 database,不然也是會請你先建 DB
php artisan migrate
// apache virtualhost 設定
編輯 /etc/apache2/sites-available/000-default.conf
將 documentroot 設為你的專案資料夾,laravel 專案的話要指到 public 那一層。
DocumentRoot /var/www/your_folder/public
// 重啟 apache
$sudo service apache2 restart
// 因為 laravel 有 .htaccess,要做一些 apache 的 rewrite
sudo a2enmod rewrite
sudo service apache2 restart
差不多這樣就可以。
也不是用 docker,開新 server 最煩的就是環境建置,一氣之下乾脆把安裝步驟都記起來,以免下次又要重建...,重新 google 很花時間成本。 QQ
Server 背景與用途說明:
1. 一般 web server,aws 的 micro instance,作業系統 Ubuntu 14.04.1 LTS
2. 用的是 Apache + MySQL + php (皆獨立開分安裝)
3. web framework 用的是 Laravel 4.2
4. 用 80 port 而已
Step:
$ sudo apt-get update
// 安裝 git
$ sudo apt-get install git
// 安裝 apache
$ sudo apt-get install apache2
// 安裝 mysql , php, 還有 php 需要用到的 mcrypt, 相關模組
$ sudo apt-get install mysql-server php5-mysql
$ sudo apt-get install php5 libapache2-mod-php5 php5-mcrypt
$ sudo apt-get install openssl
$ sudo apt-get install curl
$ sudo php5enmod mcrypt
$ sudo service apache2 restart
$ sudo apt-get install php5-cli
// 安裝 redis,裝完後要使用的話,記得下 redis-server 啟用它
$ sudo apt-get install redis-server
// 環境確認 (php, apache, mysql 是否都存在)
$ php -v
$ which mysql
$ which apache2
// mysql 連線測試
$ mysql -uroot -p你的mysql密碼
// 安裝 composer
$ curl -sS https://getcomposer.org/installer | php
// 測試 composer 安裝正常
$ composer
ubuntu@ip-XXX-XX-X-XX:~$ composer
// clone 專案到 /var/www
這中間要 git clone 要自己注意 clone 的方式是 https 還是 ssh, 如果是 ssh 要記得加入server的 ssh public key 到 git(端看你用什麼方式 git clone,我是 bitbucket)
*備註: 產生 ssh key $ ssh-keygen -t rsa
會問你一些問題,不知道就一直 enter 下去。 把 id_rsa.pub 內容複製到 git/bitbucket 的 development key 管理的地方
$ cat ~/.ssh/id_rsa.pub 然後貼到設定檔去
$ cd /var/www
$ git clone git@XXX.xxx:team/repo-name.git
或者
$ git cloen https://XXX 用打帳號密碼的方式下載
//clone 完成後,cd 專案的資料夾
$ cd /var/www/repo-name
// 先進行 composer update 下載相依的 package
$ composer update
// 對 app/storage 做 777 或 755 的權限
$ sudo chmod 0777 -R storage/
// 如果要跑 migration 建立 table 的話,記得先建好 database,不然也是會請你先建 DB
php artisan migrate
// apache virtualhost 設定
編輯 /etc/apache2/sites-available/000-default.conf
將 documentroot 設為你的專案資料夾,laravel 專案的話要指到 public 那一層。
DocumentRoot /var/www/your_folder/public
// 重啟 apache
$sudo service apache2 restart
// 因為 laravel 有 .htaccess,要做一些 apache 的 rewrite
sudo a2enmod rewrite
sudo service apache2 restart
差不多這樣就可以。
2015年4月12日 星期日
在 Laravel 以外的世界使用 Laravel 的 ORM
這篇文章應該打說 : using eloquent without Laravel,:P
因為我現在有獨立開發一個 package 的需求,可是這個 package 是要掛在 Laravel 的專案底下,為了 maintain 方便以及可以跟 Laravel 使用一樣的方式存取 Database,所以我就要在我的 package 使用 illuminate/database 這個 package。
這個 package 也就是 Laravel 在操作 database 的部分,在你自己專案的 composer.json把他 require 進來:
然後 use 他再把他實例化 (new),使用方法幾乎一摸摸一樣樣~。
參考:
https://github.com/illuminate/database
Use Laravel’s Eloquent ORM Outside Of Laravel
因為我現在有獨立開發一個 package 的需求,可是這個 package 是要掛在 Laravel 的專案底下,為了 maintain 方便以及可以跟 Laravel 使用一樣的方式存取 Database,所以我就要在我的 package 使用 illuminate/database 這個 package。
這個 package 也就是 Laravel 在操作 database 的部分,在你自己專案的 composer.json把他 require 進來:
"require": {
"illuminate/database": "*"
},
"illuminate/database": "*"
},
然後 use 他再把他實例化 (new),使用方法幾乎一摸摸一樣樣~。
參考:
https://github.com/illuminate/database
Use Laravel’s Eloquent ORM Outside Of Laravel
2015年4月11日 星期六
在 Laravel 專案下 composer require 自己私有的 Package
事情是這樣的,我現在還是使用 Laravel 4 在開發專案,因為這個案子在兩個月前就已經決定架構是採 4 了...,還沒這麼潮開始用 5 ...(要不要採用 5 我暫時認為那是給新人去決定的事,至少目前我是一人開發)。
對了因應 Web 專案越來越複雜的需求,避免太多需要一直被重複使用的 function 重寫,或是一些商業邏輯一直要被重複使用,最近我開始把一些撈資料的邏輯寫成一個 Composer Package,但因為這個 Package 不需要被公開,所以也不需要 publish 到 composer 上,然而我們公司暫時也沒有必要架一個私有的 package 管理 server,所以要達到在專案下 composer update 時去 git clone 我的 private repo 就只有修改 composer.json 了。
不看我廢話的方法你也可以參考比較快啦 XD : https://getcomposer.org/doc/05-repositories.md#using-private-repositories
composer.json 的修改如下,主要是新增一個 repositories 的 key 以及增加 require 那邊的 vendor:
首先,你要知道你的 private repo 的 url,把設定寫一寫,要注意 require 那邊也要加上你的 repo 對應的 vendor 跟 repo name。另外 clone 的時候會檢查你有沒有 clone 的權限,通常是你電腦只要有加過 ssh key 給你的 git client 就可以了。
type 的設定看你用什麼版本控制,是 git 還是 vsc 等等。
設定完成之後記得 composer update 或是 composer install,我忘記是哪個了 :P
大概是這樣。
對了因應 Web 專案越來越複雜的需求,避免太多需要一直被重複使用的 function 重寫,或是一些商業邏輯一直要被重複使用,最近我開始把一些撈資料的邏輯寫成一個 Composer Package,但因為這個 Package 不需要被公開,所以也不需要 publish 到 composer 上,然而我們公司暫時也沒有必要架一個私有的 package 管理 server,所以要達到在專案下 composer update 時去 git clone 我的 private repo 就只有修改 composer.json 了。
不看我廢話的方法你也可以參考比較快啦 XD : https://getcomposer.org/doc/05-repositories.md#using-private-repositories
composer.json 的修改如下,主要是新增一個 repositories 的 key 以及增加 require 那邊的 vendor:
首先,你要知道你的 private repo 的 url,把設定寫一寫,要注意 require 那邊也要加上你的 repo 對應的 vendor 跟 repo name。另外 clone 的時候會檢查你有沒有 clone 的權限,通常是你電腦只要有加過 ssh key 給你的 git client 就可以了。
type 的設定看你用什麼版本控制,是 git 還是 vsc 等等。
設定完成之後記得 composer update 或是 composer install,我忘記是哪個了 :P
"require": {
"laravel/framework": "4.2.*", "vendor-name/repo-name": "dev-master", },
"repositories": [{
"type": "git",
"url": "git@bitbucker_or_github:vendor-name/repo-name.git"
}],
"laravel/framework": "4.2.*", "vendor-name/repo-name": "dev-master", },
"repositories": [{
"type": "git",
"url": "git@bitbucker_or_github:vendor-name/repo-name.git"
}],
大概是這樣。
2015年4月10日 星期五
Laravel 取得上一筆/下一筆的 Query 該怎麼寫
有時候在寫一些前台的 News 的資料時,設計師畫了兩個 Button,一個是上一篇,一個是下一篇,這兩個 Button 確實是很正常的功能,可是我們後端在撈資料時,並不能順著 id (也就是流水編號) 來撈。
比方說使用者看的 id 是 20 的新聞,他的上一篇不是 id: 19,下一篇也不是 id: 21,因為上一篇可能已經刪掉了,或是下一篇其實是不發佈的狀態,因此上一篇可能是 18 也說不定,下一篇也可能是 22 也說不定,所以不應該是用流水編號來撈。
我的撈法是要以當下所看的文章 id 為基準點,上一篇的話就是小於現在的 id 下去找,然後濾出最大的 id,這樣就得到上一篇,而下一篇的話,就是大於現在的 id 往上找,然後濾出最小的那個 id。
範例:
*取得上一篇 ID
比方說使用者看的 id 是 20 的新聞,他的上一篇不是 id: 19,下一篇也不是 id: 21,因為上一篇可能已經刪掉了,或是下一篇其實是不發佈的狀態,因此上一篇可能是 18 也說不定,下一篇也可能是 22 也說不定,所以不應該是用流水編號來撈。
我的撈法是要以當下所看的文章 id 為基準點,上一篇的話就是小於現在的 id 下去找,然後濾出最大的 id,這樣就得到上一篇,而下一篇的話,就是大於現在的 id 往上找,然後濾出最小的那個 id。
範例:
*取得上一篇 ID
$prev_essay = $this->essay->where('id', '<', $id)->max('id');
*取得下一篇 ID
$next_essay = $this->essay->where('id', '>', $id)->min('id');
一般 SQL 的表示方法為:
select min(`id`) as next_id from `TABLE_NAME` where `id` > $id
select max(`id`) as prev_id from `TABLE_NAME ` where `id` < $id
以上是我的方法,至少爬過文之後覺得這個方法可行,如果有更有效率的做法,也歡迎分享一下,謝謝!
訂閱:
文章 (Atom)
Vue multiselect set autofocus and tinymce set autofocus
要在畫面一進來 focus multiselect 的方式: 參考: https://jsfiddle.net/shentao/mnphdt2g/ 主要就是在 multiselect 的 tag 加上 ref (例如: my_multiselect), 另外在 mounted...
-
最近開始覺得 Safari 大概是未來的 IE。 在使用 HTML5 的 video 播放影片時,遇到兩種影片播不出來的情況。 情況一 較少人會遇到,就是尚未更新成最新的 OS 作業系統,(我的情況是作業系統 OS X EI Capitan, safari版本: 9...
-
繼上次我寫過一篇筆記 : HTML製作edm的技巧與問題 最近發現即便我遵守一些製作edm或是email信件的規則,一樣會有在各大mail system(各大信箱,ex:Microsoft outlook, gmail, hotmail, Yahoo mail....)出現各...
-
有一次我在開branch的時候: $ git checkout -b winwu/dev 發生了這個錯誤: fatal: Not a git repository (or any of the parent directories): .git 不過,起因不是重...